R 包开发:测试通过控制台,但通过 devtools::test() 失败

Posted

技术标签:

【中文标题】R 包开发:测试通过控制台,但通过 devtools::test() 失败【英文标题】:R package development: tests pass in console, but fail via devtools::test() 【发布时间】:2021-12-23 10:01:19 【问题描述】:

我正在开发一个 R 包,它调用包 rstan 中的函数。作为 MWE,我的测试文件目前是这样设置的,使用的代码逐字取自 rstan 的示例:

library(testthat)
library(rstan)

# stan's own example
stancode <- 'data real y_mean; parameters real y; model y ~ normal(y_mean,1);'
mod <- stan_model(model_code = stancode, verbose = TRUE)
fit <- sampling(mod, data = list(y_mean = 0))
# I added this line, and it's the culprit
summary(fit)$summary

当我在控制台中或通过 RStudio 中的“运行测试”按钮运行此代码时,不会引发任何错误。但是,当我运行 devtools::test() 时,我得到:

Error (test_moments.R:11:1): (code run outside of `test_that()`)
Error in `summary(fit)$summary`: $ operator is invalid for atomic vectors

并且这个错误肯定不会发生在最后一行代码的上游,因为删除最后一行允许devtools::test() 运行而不会出现错误。我正在运行最新的软件包 devtoolsrstan

【问题讨论】:

我很想知道拒绝投票的原因,以告知未来的问题。 我不确定您为什么被否决,但您的问题可以通过包含创建包含失败测试的最小 R 包的代码来改进。 好点。谢谢。 【参考方案1】:

似乎devtools::test 在 S4 调度无法以通常方式工作的设置中评估测试代码,至少对于您在测试文件中显式加载的包(在本例中为 rstan)。因此,summary 调度到summary.default,而不是在rstan 中为类"stanfit" 实现的S4 方法。

您看到的行为可能与 testthat 存储库中的 this issue 相关,这似乎尚未解决。

这是一个试图阐明正在发生的事情的最小示例,展示了一种可能(诚然不方便)的解决方法。

pkgname <- "foo"
usethis::create_package(pkgname, rstudio = FALSE, open = FALSE)
setwd(pkgname)

usethis::use_testthat()
path_to_test <- file.path("tests", "testthat", "test-summary.R")
text <- "test_that('summary', 
  library('rstan')
  stancode <- 'data real y_mean; parameters real y; model y ~ normal(y_mean,1);'
  mod <- stan_model(model_code = stancode, verbose = TRUE)
  fit <- sampling(mod, data = list(y_mean = 0))

  expect_identical(class(fit), structure('stanfit', package = 'rstan'))
  expect_true(existsMethod('summary', 'stanfit'))

  x <- summary(fit)
  expect_error(x$summary)
  expect_identical(x, summary.default(fit))
  print(x)

  f <- selectMethod('summary', 'stanfit')
  y <- f(fit)
  str(y)
)
"
cat(text, file = path_to_test)

devtools::test(".") # all tests pass

如果您的包实际上导入了rstan(在NAMESPACE 意义上,而不是在DESCRIPTION 意义上),那么S4 调度似乎工作正常,大概是因为devtools 将您的包及其依赖项加载到“运行任何测试之前的正确”方式。

cat("import(rstan)\n", file = "NAMESPACE")
newtext <- "test_that('summary', 
  stancode <- 'data real y_mean; parameters real y; model y ~ normal(y_mean,1);'
  mod <- stan_model(model_code = stancode, verbose = TRUE)
  fit <- sampling(mod, data = list(y_mean = 0))

  x <- summary(fit)
  f <- selectMethod('summary', 'stanfit')
  y <- f(fit)
  expect_identical(x, y)
)
"
cat(newtext, file = path_to_test)

## You must restart your R session here. The current session 
## is contaminated by the previous call to 'devtools::test',
## which loads packages without cleaning up after itself...

devtools::test(".") # all tests pass

如果您的测试失败并且您的包导入rstan,那么可能会发生其他情况,但如果没有您的包的最低版本,则很难诊断。

免责声明:不遗余力地导入 rstan 以解决相对模糊的 devtools 问题应该被视为更多的黑客攻击而不是修复,并相应地记录...

【讨论】:

完美!在 NAMESPACE 中使用 import(rstan) 而不是 importFrom(...) 解决了它。非常感谢。 我实际上假设您没有import importFrom,并认为在您的NAMESPACE 中包含任何一个就足够了。有趣的是,只有import 有效。无论如何,请注意几点: (1) 如果您使用roxygen2 记录您的包,那么您不应该手动编辑NAMESPACE。你只需要在你的包中某个地方#' @import rstan。 (2) 您可能想要记录为什么您使用import 而不是importFrom,因为我的回答依赖于(据我所知)devtools 的未记录行为...

以上是关于R 包开发:测试通过控制台,但通过 devtools::test() 失败的主要内容,如果未能解决你的问题,请参考以下文章

使用 Selenium Webdriver 控制 Chrome Devtools

脚本从 R 运行,但不是通过命令行

在Edge上安装与测试Vue devtools开发者工具

通过 JS 打开“检查元素”窗口

解决新版本R3.6.0不能加载devtools包问题

R 包失败 devtools::check,因为“找不到函数”,即使该函数已导入 NAMESPACE