【发布时间】:2020-06-03 14:49:42
【问题描述】:
我正在通过R CMD check 运行我的包,唯一(剩余的)警告如下:
W checking for unstated dependencies in 'tests' (4.4s)
'::' or ':::' import not declared from: 'devtools'
在对这个看似荒谬的警告困惑了很长时间之后,我意识到它来自我的“测试管理器”脚本(请参阅下面的需要它的原因)。这是文件pkg/tests/testthat.R,而测试本身在pkg/tests/testthat/。
# testthat.R
sink(stderr(), type = "output")
x <- tryCatch(
{
x <- data.frame(devtools::test()) # here's the problem!
as.numeric(sum(x$failed) > 0)
},
error = function(e) {
1
}
)
sink(NULL, type = "output")
cat(1)
如果我注释掉整个文件,R CMD check 警告就会消失。
然后是奇怪的部分:如果我只用 test() 替换 devtools::test(),R CMD check 警告就会消失。
然而,这个“管理器”脚本的目的是被一个 git pre-commit 钩子调用(通过Rscript)。这样,我可以运行所有测试以确保提交是稳定的。因此,我不能使用test(),因为通过Rscript 运行脚本时不会加载devtools。
我尝试了一些方法来满足R CMD check 和被Rscript 调用:
- 使用
library(devtools)不起作用(引发package not found错误); - 将
testthat.R移出/tests/文件夹并移至顶层。这会杀死R CMD check警告,但现在会抛出一个注释:Non-standard file/directory found at top level: 'testthat.R',因此并不完全令人满意(尤其是因为将其保存在/tests/目录中似乎更符合逻辑); - 测试显然已由
R CMD check加载的函数以确定行为。由于使用裸test()有效,我假设devtools已加载,因此将以下内容添加到文件中(并在有问题的行上使用runTests)。逻辑是,如果我们能找到test(),就使用它。如果我们不能,那么这可能不是R CMD check,所以我们可以使用全名。
if (length(find("test")) == 0) {
runTests <- devtools::test()
} else {
runTests <- test()
}
不幸的是,这只会让事情变得更糟:警告仍然存在,我们还在if-else 块上收到错误:
> if (length(find("test")) == 0) {
+ runTests <- devtools::test()
+ } else {
+ runTests <- test()
+ }
Error in loadNamespace(name) : there is no package called 'devtools'
Calls: :: ... loadNamespace -> withRestarts -> withOneRestart -> doWithOneRestart
为什么devtools::test() 会在这里抛出错误,而我只是在有问题的行上发出警告。
- 类似地,使用
testthat::skip()。也不行。
那么,我该怎么做才能同时满足R CMD check 和被Rscript 调用?有没有办法告诉R CMD check 忽略这个文件?
作为记录,这是我的 git pre-commit 钩子,以防万一它可以重新制定以通过其他方式解决这个问题
#!/bin/sh
R_USER="D:/Users/wasabi/Documents"
export R_USER
# check that Rscript is accessible via PATH; fail otherwise
command -v Rscript >/dev/null || {
echo "Rscript must be accessible via PATH. Commit aborted.";
exit 1;
};
# check whether there are unstaged changes. If so, stash them.
# This allows the tests to run only on previously committed or
# indexed (added on this commit) changes.
hasChanges=$(git diff)
if [ -n "$hasChanges" ]; then
git stash push --keep-index
fi
exitCode=$(Rscript tests/testthat.R)
# remember to unstash any unstaged changes
if [ -n "$hasChanges" ]; then
git stash pop
fi
exit $exitCode
【问题讨论】: