ropensci-review-tools/autotest

GitHub: ropensci-review-tools/autotest

一款针对 R 包的自动化变异测试工具,通过修改函数参数输入来发现包在异常输入下的潜在问题。

Stars: 54 | Forks: 5

# autotest [![R-CMD-check](https://static.pigsec.cn/wp-content/uploads/repos/cas/0c/0c53c9f366c107b6cef02195f562e6d536e7b019a71c67162cb09f76546983df.svg)](https://github.com/ropensci-review-tools/autotest/actions/workflows/R-CMD-check.yaml) [![Codecov test coverage](https://codecov.io/gh/ropensci-review-tools/autotest/graph/badge.svg)](https://app.codecov.io/gh/ropensci-review-tools/autotest) [![Project Status: Concept](https://www.repostatus.org/badges/latest/concept.svg)](https://www.repostatus.org/#concept) 针对 R 包的自动变异测试。此处的变异是指改变函数调用的输入(参数)。`autotest` 的工作原理主要是抓取所有函数已记录的示例,并对输入到这些函数的参数进行变异。 ## 安装说明 安装此包最简单的方法是通过相关的 [`r-universe`](https://ropensci-review-tools.r-universe.dev/ui#builds)。 如该处所示,只需通过以下命令启用该 universe: ``` options (repos = c ( ropenscireviewtools = "https://ropensci-review-tools.r-universe.dev", CRAN = "https://cloud.r-project.org" )) ``` 然后使用常规方法进行安装: ``` install.packages ("autotest") ``` 或者,也可以通过运行以下任意一行命令来安装该包: ``` # install.packages("remotes") remotes::install_git ("https://codeberg.org/ropensci-review-tools/autotest") remotes::install_git ("https://codefloe.com/ropensci-review-tools/autotest") remotes::install_gitlab ("ropensci-review-tools/autotest") remotes::install_github ("ropensci-review-tools/autotest") remotes::install_git ("https://git.sr.ht/~mpadge/autotest") remotes::install_bitbucket ("mpadge/autotest") ``` 接下来就可以用常规方式加载该包: ``` library (autotest) ``` ## 使用方法 使用该包最简单的方法是 ``` x <- autotest_package ("") ``` [`autotest_package()` 函数](https://docs.ropensci.org/autotest/reference/autotest_package.html) 的主要参数,可以是已安装包的名称,也可以是包含包源代码的本地目录路径。返回的结果是一个 `data.frame`,其中包含在包 `auotest`-ing 过程中发出的错误、警告和其他诊断信息。该函数还有一个附加参数 `functions`,用于将测试限制在指定的函数上。 默认情况下,[`autotest_package()`](https://docs.ropensci.org/autotest/reference/autotest_package.html) 会返回应用于包的所有测试列表,但并不会实际运行它们。要执行这些测试,请将参数 `test` 设置为 `TRUE`。只有当函数的表现与预期不符(无论是触发错误、警告还是下文描述的其他行为)时,才会返回相应的测试结果。`autotest_package()` 的理想行为是什么都不返回(准确地说,返回 `NULL`),这表示所有测试均已成功通过。请参阅 [主包 vignette](https://docs.ropensci.org/autotest/articles/autotest.html) 以获取该包的入门指南。 ## 测试内容是什么? 该包包含一个函数,用于列出当前已实现的所有测试。 ``` autotest_types () #> # A tibble: 27 × 8 #> type test_name fn_name parameter parameter_type operation content test #> #> 1 dummy rect_as_other rectangular Convert … "check… TRUE #> 2 dummy rect_compare_… rectangular Convert … "expec… TRUE #> 3 dummy rect_compare_… rectangular Convert … "expec… TRUE #> 4 dummy rect_compare_… rectangular Convert … "expec… TRUE #> 5 dummy extend_rect_c… rectangular Extend e… "(Shou… TRUE #> 6 dummy replace_rect_… rectangular Replace … "(Shou… TRUE #> 7 dummy vector_to_lis… vector Convert … "(Shou… TRUE #> 8 dummy vector_custom… vector Custom c… "(Shou… TRUE #> 9 dummy double_is_int numeric Check wh… "int p… TRUE #> 10 dummy trivial_noise numeric Add triv… "(Shou… TRUE #> # ℹ 17 more rows ``` 该函数会返回一个 [`tibble`](https://tibble.tidyverse.org),其中描述了 27 种独特的测试。当 `test = FALSE` 时,[`autotest_package()`](https://docs.ropensci.org/autotest/reference/autotest_package.html) 的默认行为会使用这些测试类型来确定将哪些测试应用于每个参数和函数。通过将 `test` 列中的值设置为 `FALSE`,可以利用 [`autotest_types()`](https://docs.ropensci.org/autotest/reference/autotest_types.html) 返回的表格来选择性地关闭测试,如下所示。 ## 工作原理是什么? 该包通过从所有 `.Rd` 帮助文件中抓取已记录的示例来工作,并利用这些示例识别所有函数的所有参数类型。因此,在使用前,首先需要确保所有参数的用法都在示例代码中进行了演示。 如上所述,也可以通过 `functions` 和 `exclude` 参数选择性地将测试应用于特定函数。`functions` 用于指定要包含在测试中的函数,而 `exclude` 用于指定要从测试中排除的函数。以下代码对此进行了演示。 ``` x <- autotest_package (package = "stats", functions = "var", test = FALSE) #> #> ── autotesting stats ── #> #> ✔ [1 / 6]: var #> ✔ [2 / 6]: cor #> ✔ [3 / 6]: cor #> ✔ [4 / 6]: cov #> ✔ [5 / 6]: cov #> ✔ [6 / 6]: cor print (x) #> # A tibble: 170 × 9 #> type test_name fn_name parameter parameter_type operation content test #> #> 1 warning par_is_demo… var use Check th… Exampl… TRUE #> 2 warning par_is_demo… cov y Check th… Exampl… TRUE #> 3 dummy trivial_noi… var x numeric Add triv… (Shoul… TRUE #> 4 dummy vector_cust… var x vector Custom c… (Shoul… TRUE #> 5 dummy vector_to_l… var x vector Convert … (Shoul… TRUE #> 6 dummy negate_logi… var na.rm single logical Negate d… (Funct… TRUE #> 7 dummy subst_int_f… var na.rm single logical Substitu… (Funct… TRUE #> 8 dummy subst_char_… var na.rm single logical Substitu… should… TRUE #> 9 dummy single_par_… var na.rm single logical Length 2… Should… TRUE #> 10 dummy return_succ… var (return … (return objec… Check th… TRUE #> # ℹ 160 more rows #> # ℹ 1 more variable: yaml_hash ``` 测试 `var` 函数时也会同时测试 `cor` 和 `cov`,因为它们都记录在同一个 `.Rd` 帮助文件中。输入 `?var` 会显示其帮助主题是 `cor`,并且示例中包含 `var`、`cor` 和 `cov` 这三个函数。该结果详细列出了将应用于 `stats` 包中 `var` 函数的 170 项测试。 在实际应用时,这 170 项测试产生了以下结果: ``` y <- autotest_package (package = "stats", functions = "var", test = TRUE) #> ── autotesting stats ── #> #> ✔ [1 / 6]: var #> ✔ [2 / 6]: cor #> ✔ [3 / 6]: cor #> ✔ [4 / 6]: cov #> ✔ [5 / 6]: cov #> ✔ [6 / 6]: cor print (y) #> # A tibble: 25 × 9 #> type test_name fn_name parameter parameter_type operation content test #> #> 1 warning par_is_d… var use Check th… "Examp… TRUE #> 2 warning par_is_d… cov y Check th… "Examp… TRUE #> 3 diagnostic vector_t… var x vector Convert … "Funct… TRUE #> 4 diagnostic subst_in… var na.rm single logical Substitu… "(Func… TRUE #> 5 diagnostic vector_t… var x vector Convert … "Funct… TRUE #> 6 diagnostic vector_t… var y vector Convert … "Funct… TRUE #> 7 diagnostic single_c… cor use single charac… upper-ca… "is ca… TRUE #> 8 diagnostic single_c… cor method single charac… upper-ca… "is ca… TRUE #> 9 diagnostic vector_c… cor x vector Custom c… "Funct… TRUE #> 10 diagnostic vector_c… cor x vector Custom c… "Funct… TRUE #> # ℹ 15 more rows #> # ℹ 1 more variable: yaml_hash ``` 在最初的 170 项测试中,只有 25 项产生了意外行为。实际上,只有 5 种测试类型产生了这 25 个结果: ``` unique (y$operation) #> [1] "Check that parameter usage is demonstrated" #> [2] "Convert vector input to list-columns" #> [3] "Substitute integer values for logical parameter" #> [4] "upper-case character parameter" #> [5] "Custom class definitions for vector input" ``` 其中一项涉及将向量转换为列表列表示(通过 `I(as.list())`)。尽管这样做相对简单,但很少有包能够接受这种类型的输入。 以下命令行演示了在对包进行 `autotest`-ing 时如何关闭这些测试。上文中用于提取所有测试类型信息的 `autotest_types()` 函数,也可以接受一个单独的参数,该参数列出了任何需要关闭的测试的 `test_name` 条目。 ``` types <- autotest_types (notest = "vector_to_list_col") y <- autotest_package ( package = "stats", functions = "var", test = TRUE, test_data = types ) #> ── autotesting stats ── #> #> ✔ [1 / 6]: var #> ✔ [2 / 6]: cor #> ✔ [3 / 6]: cor #> ✔ [4 / 6]: cov #> ✔ [5 / 6]: cov #> ✔ [6 / 6]: cor print (y) #> # A tibble: 22 × 9 #> type test_name fn_name parameter parameter_type operation content test #> #> 1 warning par_is_d… var use Check th… Exampl… TRUE #> 2 warning par_is_d… cov y Check th… Exampl… TRUE #> 3 diagnostic subst_in… var na.rm single logical Substitu… (Funct… TRUE #> 4 diagnostic single_c… cor use single charac… upper-ca… is cas… TRUE #> 5 diagnostic single_c… cor method single charac… upper-ca… is cas… TRUE #> 6 diagnostic vector_c… cor x vector Custom c… Functi… TRUE #> 7 diagnostic vector_c… cor x vector Custom c… Functi… TRUE #> 8 diagnostic single_c… cor method single charac… upper-ca… is cas… TRUE #> 9 diagnostic single_c… cor use single charac… upper-ca… is cas… TRUE #> 10 diagnostic single_c… cor use single charac… upper-ca… is cas… TRUE #> # ℹ 12 more rows #> # ℹ 1 more variable: yaml_hash ``` 这些测试仍会从 `autotest_package()` 中返回,但其 `test` 为 `FALSE`,表明它们并未运行,并且 `type` 为 “no_test” 而不是之前的 “diagnostic”。 ## `autotest` 可以自动在我的 `tests` 目录中创建测试吗? 暂时还不能,但应该很快就能实现。与此同时,在 [主包函数](https://docs.ropensci.org/autotest/reference/index.html) 中列出了 [`testthat`](https://testthat.r-lib.org) expectations,这使得 `autotest` 能够被用在包的测试套件中。 ## 先前工作 1. 用于 Python 的 [`great-expectations`](https://github.com/great-expectations/great_expectations) 框架,在[这篇 medium 文章](https://medium.com/@expectgreatdata/down-with-pipeline-debt-introducing-great-expectations-862ddc46782a)中有所介绍。 2. 用于 Haskell 的 [`QuickCheck`](https://hackage.haskell.org/package/QuickCheck) 3. 用于 Ruby 的 [`mutate`](https://github.com/mbj/mutant) 4. 用于 R 代码本身变异的 [`mutant`](https://github.com/ropensci/mutant)
标签:R语言, SOC Prime, 变异测试, 开发工具