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()
运行而不会出现错误。我正在运行最新的软件包 devtools
和 rstan
。
【问题讨论】:
我很想知道拒绝投票的原因,以告知未来的问题。 我不确定您为什么被否决,但您的问题可以通过包含创建包含失败测试的最小 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() 失败的主要内容,如果未能解决你的问题,请参考以下文章