如何为建议的包编写单元测试?
How to write unit tests for suggested packages?
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
(或任何其他单元测试框架)?
tl;博士
测试使用require(knitr)
失败时后面的b运行ch,使用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))))
据我了解,您有一个包含两个 b运行ches 的函数,一个在 require(knitr)
成功的 R 会话中执行,另一个在它成功的会话中执行失败。然后您想要从单个 R 实例测试此函数 "both ways",其中 knitr 实际上位于 .libPaths()
.
所以基本上你需要一些方法来暂时屏蔽 require(knitr)
的调用,使 knitr 的实际存在不可见。完全临时重置 .libPaths()
返回的值看起来很有希望,但似乎不可能。
另一个有前途的途径是在从 NULL
调用 require()
时以某种方式重置 lib.loc
的默认值(这意味着“使用 .libPaths()
的值)到knitr 不可用的其他一些位置。您不能通过覆盖 base::require()
来完成此操作,也不能(在包中)通过定义本地掩码版本到达那里require()
与期望值 lib.loc
。
不过,看起来您可以使用 trace()
临时修改 require()
(将其隐藏到 knitr 的可用性设置 lib.loc=R.home()
)。然后执行 untrace()
将 require()
恢复为原版,然后继续查找 knitr。
这是我测试过的虚拟包中的样子。首先是一个 R 函数,它允许我们沿着两个 b运行ches
测试是否成功
## $PKG_SRC/R/hello.R
hello <- function(x=1) {
if(require(knitr)) {
x==2
} else {
x==3
}
}
然后进行一些测试,每个 b运行ch:
## $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")
建立了一个源码目录,将这两个文件复制进去,在DESCRIPTION
文件中添加Suggests: knitr
,然后运行 devtools::install()
和 devtools::check()
从适当的目录。该软件包安装得很好,并通过了所有检查。
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
(或任何其他单元测试框架)?
tl;博士
测试使用require(knitr)
失败时后面的b运行ch,使用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))))
据我了解,您有一个包含两个 b运行ches 的函数,一个在 require(knitr)
成功的 R 会话中执行,另一个在它成功的会话中执行失败。然后您想要从单个 R 实例测试此函数 "both ways",其中 knitr 实际上位于 .libPaths()
.
所以基本上你需要一些方法来暂时屏蔽 require(knitr)
的调用,使 knitr 的实际存在不可见。完全临时重置 .libPaths()
返回的值看起来很有希望,但似乎不可能。
另一个有前途的途径是在从 NULL
调用 require()
时以某种方式重置 lib.loc
的默认值(这意味着“使用 .libPaths()
的值)到knitr 不可用的其他一些位置。您不能通过覆盖 base::require()
来完成此操作,也不能(在包中)通过定义本地掩码版本到达那里require()
与期望值 lib.loc
。
不过,看起来您可以使用 trace()
临时修改 require()
(将其隐藏到 knitr 的可用性设置 lib.loc=R.home()
)。然后执行 untrace()
将 require()
恢复为原版,然后继续查找 knitr。
这是我测试过的虚拟包中的样子。首先是一个 R 函数,它允许我们沿着两个 b运行ches
测试是否成功## $PKG_SRC/R/hello.R
hello <- function(x=1) {
if(require(knitr)) {
x==2
} else {
x==3
}
}
然后进行一些测试,每个 b运行ch:
## $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")
建立了一个源码目录,将这两个文件复制进去,在DESCRIPTION
文件中添加Suggests: knitr
,然后运行 devtools::install()
和 devtools::check()
从适当的目录。该软件包安装得很好,并通过了所有检查。