R中的包可以在其他包上具有不同类型的依赖关系。其中一些类型表明了硬性要求,即Depends
,Imports
和LinkingTo
。
但是,还有第二类表明依赖性较弱,即Suggests
和Enhances
。在这两种情况下,如果建议/增强包可用,该包提供了额外的功能。
以下是一个具体示例:包checkpoint
导入knitr
因为knitr
帮助checkpoint
解析rmarkdown
个文件。
但现在我正在考虑将knitr
更改为Suggests
依赖关系,即仅在实际安装knitr
时才提供此功能。
对于正确的单元测试,这意味着我必须测试两种情况:
knitr
可用,则执行操作。knitr
不可用,则抛出警告并不执行任何操作。实际的R代码很简单:
if(require(knitr)) {
do_stuff()
} else {
message("blah")
}
问题
但是如何为这两种情况设置单元测试?
我看到它的方式,检查require(knitr)
的简单事实将加载knitr
包,如果它在本地库中可用。
因此,要测试案例1,我必须在本地安装knitr
,这意味着我无法测试案例2。
是否有办法为此用例配置testthat
(或任何其他单元测试框架)?
答案 0 :(得分:3)
要在使用require(knitr)
失败时测试分支,请使用trace()
临时修改require()
,以便找不到 knitr ,甚至如果它出现在.libPaths()
上。具体而言,在require()
的正文中,将lib.loc=
的值重置为指向R.home()
- 不包含knitr
包的现有目录。
这似乎在包中的效果与在运行以下内容的交互式会话中一样:
find.package("knitr")
trace("require", quote(lib.loc <- R.home()), at=1)
isTRUE(suppressMessages(suppressWarnings(require(knitr))))
untrace("require")
isTRUE(suppressMessages(suppressWarnings(require(knitr))))
据我所知,你有一个带有两个分支的函数,一个在R会话中执行,require(knitr)
成功,另一个在失败的会话中执行。然后你想要测试这个功能&#34;两种方式&#34;来自单个R实例,其中 knitr 实际上在.libPaths()
上。
所以基本上你需要某种方法暂时将通话require(knitr)
视为 knitr 的实际存在。完全暂时重置.libPaths()
返回的值看起来很有希望,但似乎不可能。
另一个有希望的途径是以某种方式重置lib.loc
来自require()
的{{1}}调用的默认值(这意味着&#34;使用NULL
的值)到 knitr 不可用的其他位置。您无法通过覆盖.libPaths()
来实现此目的,也不能(在包中)通过定义具有所需值base::require()
的{{1}}的本地屏蔽版本来实现此目的。
但是,看起来您可以使用require()
暂时修改lib.loc
(通过设置{将其隐藏到 knitr &#39; s可用性) {1}})。然后执行trace()
将require()
恢复为vanilla版本,该版本将继续并找到 knitr 。
这是我在测试过的虚拟包装中的样子。首先是一个R函数,它允许我们测试两个分支的成功
lib.loc=R.home()
然后进行几个测试,每个分支一个:
untrace()
为了测试这一点,我使用require()
设置了一个源目录,复制了这两个文件,将## $PKG_SRC/R/hello.R
hello <- function(x=1) {
if(require(knitr)) {
x==2
} else {
x==3
}
}
添加到## $PKG_SRC/inst/tests/testme.R
## Test the second branch, run when require(knitr) fails
trace("require", quote(lib.loc <- R.home()), at=1)
stopifnot(hello(3))
untrace("require")
## Test the first branch, run when require(knitr) succeeds
stopifnot(hello(2))
文件,然后运行pkgKitten::kitten("dummy")
和相应目录中的Suggests: knitr
。软件包安装得很好,并通过了所有检查。