【问题标题】:testthat fails within devtools::check but works in devtools::testtestthat 在 devtools::check 中失败,但在 devtools::test 中有效
【发布时间】:2017-06-10 07:56:19
【问题描述】:

有没有办法重现devtools::check使用的环境?

我的问题是我的测试在 devtools::test() 下工作,但在 devtools::check() 内失败。我现在的问题是,如何找到问题。 check 的报告只打印了错误日志的最后几行,我找不到完整的测试报告。

checking tests ... ERROR
Running the tests in ‘tests/testthat.R’ failed.
Last 13 lines of output:
...

我知道checktest 相比使用了不同的环境,但我不知道应该如何调试这些问题,因为它们根本无法重现。特别是几个月前运行的这些测试,所以不知道在哪里寻找问题。

编辑

实际上我试图找到我的问题并找到了解决方案。但要发布我的解决方案,我必须添加更多细节。

所以我的测试总是失败,因为我正在测试一个 Markdown 脚本,如果它运行没有错误,然后我正在检查一些环境变量是否设置正确。这些是我使用脚本计算的结果以及我设置的标准设置。因此,如果我在开发后忘记更改某些设置,我想得到警告......

无论如何,因为它是一个降价脚本,我不得不提取代码,我使用这篇帖子中的 cmets knitr: run all chunks in an Rmarkdown document 使用 knitr::purl 获取代码并使用 sys.source 执行它。

runAllChunks <- function(rmd, envir=globalenv()){
  # as found here https://stackoverflow.com/questions/24753969
  tempR <- tempfile(tmpdir = '.', fileext = ".R")
  on.exit(unlink(tempR))
  knitr::purl(rmd, output=tempR, quiet=TRUE)
  sys.source(tempR, envir=envir)
}

由于某种原因,这可能会在几周后产生错误(不确定我最近安装了哪些新软件包...)。但由于有一条新评论,我可以使用knitr::knit,它也执行代码,这按预期工作,现在我的测试不再抱怨。

所以最后,我不知道问题到底出在哪里,但现在可以了。

【问题讨论】:

    标签: r devtools testthat


    【解决方案1】:

    我最近遇到了类似的问题,我的测试失败了(devtools::test() 成功,devtools::check() 失败)。我不知道这个解决方案是否一定能解决上述问题,但它应该有助于追踪类似的问题。

    就我而言,问题最终归结为使用需要Suggests 中列出的包而不是Imports/Depends 中的函数。 特别是,我的函数称为@ 987654326@,当我试图将as = "parsed" 参数传递给它时,它坏了。事实证明,as = "parsed" 使用建议的包 readr 来读取 csv,我需要将其添加到我的依赖项中以使 devtools::check() 工作。

    【讨论】:

    • 您能否详细说明一下,这不值得devtools 上的公关吗?我遇到了类似的问题,而且解决起来并不容易。
    • 我当时并没有想到(我只是想在这里记录我的经验),但至少打开一个关于抛出更好的错误消息的问题可能是值得的。澄清一下:我看到的是,如果您依赖包 A,但使用 A 中直接使用包 B 的函数,则会出现问题。如果 A 建议 B,那么它将通过检查。但如果 B 未在您的依赖项中声明,test() 将工作,因为它是交互式的,但 check() 将失败,因为它从一个完全干净的状态开始。
    【解决方案2】:

    这是带有 testthat 的 known issue。解决方法是在tests/testthat.R 的第一行添加以下内容:

    Sys.setenv(R_TESTS="")
    

    【讨论】:

    • 其实这并不能解决问题。和以前一样的问题......仍然无法读取testthat执行的日志:-(
    【解决方案3】:

    如果它对其他人有帮助,这对我有用

    1. 重新安装所有相关软件包。例如。 install.packages("testthat", "dplyr", "lubridate", "stringr")(我包含了我的包使用的所有包)
    2. 关闭 RStudio 并重新打开

    然后所有测试都通过了

    【讨论】:

      【解决方案4】:

      我花了 太多 太长时间来研究这个错误,所以希望我能在未来帮助别人。我想补充一点,在我的函数中使用 ggplot2::autoplot() 时遇到了这个错误,它要求我将 @import ggfortify 添加到我的函数的 Roxygen 骨架部分。

      【讨论】:

        【解决方案5】:

        我遇到了同样的问题,我的测试在 devtools::check() 下失败,而在 testthat::test() 下没有失败

        以上都不适用于我的问题,所以我决定也在这里发布我的问题和解决方案。但首先是我的经验中的一些注意事项:

        devtools::check() 确实 - 看起来 - 比你自己的书面测试更深入的错误检查。

        现在开始我的代码设置。我有一个用于从两个不同文件中检索值的函数。这些文件包含命名配置文件,每个配置文件具有一组值。但是配置文件的名称不同,具体取决于文件:

        示例文件:

        file_one 的内容:

        [default]
        value_A = "foo"
        value_B = "bar"
        value_C = "baz"
        
        [peter]
        value_A = "oof"
        value_B = "rab"
        value_C = "zab"
        

        file_two 的内容:

        [default]
        value_X = "fuzzly"
        value_Z = "puzzly"
        
        [profile peter]
        value_X = "fuzzly"
        value_Z = "puzzly"
        

        如您所见,当涉及到命名配置文件时,文件 2 中的命名是否遵循另一个命名约定。配置文件写在“[]”中,两个文件中的默认配置文件始终是“[默认]”。但是一旦涉及到命名配置文件,它就只是在一个文件中使用“[name]”,然后在另一个文件中使用“[profile name]”。

        现在我已经构建了这样的功能(简化):

        get_value <- function(file_content, what, profile) {
          file_content <- readr::read_lines(file)
          all_profiles_at <- grep("\\[.*\\]", file_content)
          profile_regex <- paste0("\\[",if(file_content == "file_two" && profile != "default") "profile ",profile,"\\]")
          profile_at <- grep(profile_regex, file_content)
          profile_ends_at <- if(profile_at == max(all_profiles_at)) length(file_content) else all_profiles_at[grep(paste0("^",profile_at,"$"), all_profiles_at) + 1] -1
          profile_content <- file_content[profile_at:profile_ends_at]
          whole_what <- stringr::str_replace_all(profile_content[grep(paste0("^",what,".*"), profile_content)], " ", "")
          return(stringr::str_sub(whole_what, stringr::str_length(paste0(what,"=."))))
        }
        

        使用此代码,我的测试运行顺利,甚至 check() 也没有发现任何问题。

        虽然整个代码都在演变,但我认为我应该事先阅读文件内容,并只将已读取的 read_in 内容提供给函数,以避免代码重复。所以我改变了这样的功能:

        get_value <- function(file, what, profile) {
          is_file_two <- is_file_two(file_content)
          all_profiles_at <- grep("\\[.*\\]", file_content)
          profile_regex <- paste0("\\[",if(file_content == "file_two" && profile != "default") "profile ",profile,"\\]")
          profile_at <- grep(profile_regex, file_content)
          profile_ends_at <- if(profile_at == max(all_profiles_at)) length(file_content) else all_profiles_at[grep(paste0("^",profile_at,"$"), all_profiles_at) + 1] -1
          profile_content <- file_content[profile_at:profile_ends_at]
          whole_what <- stringr::str_replace_all(profile_content[grep(paste0("^",what,".*"), profile_content)], " ", "")
          return(stringr::str_sub(whole_what, stringr::str_length(paste0(what,"=."))))
        }   
        

        您可能会注意到,我只更改了函数主体的第一行,而 if 条件保持不变 - 我的错误!

        但是我的测试没有抛出错误,因为 if 条件仍然有效。即使 'file_content == "file_two"' 部分现在生成了一个逻辑向量,并且 if() ... else ... 通常会在逻辑长度 > 1 时引发警告。带有 && 的特殊构造不会抛出这样的错误,因为它返回一个 length(1) 逻辑:

        # with warning
        if(c(FALSE, FALSE, FALSE)) "Done!" else "Not done!"
        # no warning:
        if(c(FALSE, FALSE, FALSE) && TRUE) "Done!" else "Not done!"
        

        这就是为什么我使用 testthat::test() 进行的测试仍然有效。

        但是 devtools::check() 在我的代码中发现了这个缺陷并且测试失败了!

        FAILURE_REPORT 的那部分向我展示了我的错误:

        [...]
            where 41: test_check("my_package_name")
            
             --- value of length: 18 type: logical ---
             [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
            [13] FALSE FALSE FALSE FALSE FALSE FALSE
             --- function from context ---
        [...]
        

        结论: testthat::test() 很棒!检查您的代码是否仍在运行。但是 devtools::check() 更深入 - 当您的测试通过 testthat::test() 但因 devtools::check() 失败时,您的代码中可能存在一些更深层次的错误和缺陷,您必须注意!

        【讨论】:

          【解决方案6】:

          所以正如我上面刚刚提到的,我将我的一些代码更改为不再使用knitr::purl,而是使用knitr::knit,这解决了我的问题。

          expect_error(f <- runAllChunks('010_main_lfq_analysis.Rmd'), NA)
          expect_error(f <- knitr::knit('010_main_lfq_analysis.Rmd', output='jnk.R', quiet=TRUE, envir=globalenv()), NA)
          

          【讨论】:

            【解决方案7】:

            这也可能发生在以下情况:您已经在R 中加载了一个库,并且您正在引用该库中没有命名空间绑定的函数。例如,假设您在测试文件中使用来自Matrixnnzero() 函数,并且碰巧也已经使用library(Matrix) 加载了Matrix 包。然后devtools::test() 将通过但devtools::check() 失败。使用Matrix::nnzero() 应该可以解决问题。

            【讨论】:

              猜你喜欢
              • 2020-02-18
              • 2018-03-02
              • 1970-01-01
              • 2020-10-13
              • 2020-09-01
              • 2014-03-07
              • 2020-10-30
              • 2021-04-01
              • 2019-08-31
              相关资源
              最近更新 更多