8

R 中的包可以对其他包有不同类型的依赖。其中一些类型表示硬要求,DependsImportsLinkingTo

但是,还有第二个类别表示更软的依赖关系,即SuggestsEnhances。在这两种情况下,如果建议的/增强的软件包可用,该软件包会提供额外的功能。

这是一个具体的例子:包checkpoint导入knitr是因为knitr有助于checkpoint解析rmarkdown文件。

但是现在我正在考虑更改knitr为依赖项,即仅在实际安装Suggests时才提供此功能。knitr

对于正确的单元测试,这意味着我必须测试两种情况:

  1. 如果knitr有空,那就做事。
  2. 如果knitr不可用,则抛出警告并且什么也不做

实际的 R 代码很简单:

if(require(knitr)) {
  do_stuff()
} else {
  message("blah")
}

问题

但是如何为这两种情况设置单元测试呢?

在我看来,如果包在本地库中可用,检查的简单事实require(knitr)将加载包。knitr

因此,要测试案例 1,我必须在knitr本地安装,这意味着我无法测试案例 2。

有没有办法testthat为这个用例配置(或任何其他单元测试框架)?

4

1 回答 1

3

tl;博士

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))))

据我了解,您有一个具有两个分支的函数,一个在require(knitr)成功的 R 会话中执行,另一个在失败的会话中执行。然后,您希望从knitr实际上打开的单个 R 实例“双向”测试此功能.libPaths()

所以基本上你需要一些方法来暂时隐藏对knitrrequire(knitr)实际存在的调用。完全暂时重置看起来很有希望的返回值,但似乎不可能。.libPaths()

另一个有希望的途径是以某种方式将lib.locin 调用的默认值重置为require()from NULL(这意味着“使用 的值)到knitr.libPaths()不可用的其他位置。你不能通过覆盖来实现这一点,也不能(在包中)可以您可以通过定义具有所需值 的本地掩码版本来到达那里。base::require()require()lib.loc

不过,看起来您可以使用trace()to 临时修改require()(通过设置将其蒙蔽到knitr的可用性lib.loc=R.home())。然后untrace()恢复require()到香草版本,它将继续找到knitr

这是我测试过的虚拟包中的样子。首先是一个 R 函数,它允许我们沿着两个分支测试是否成功

## $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到文件中,DESCRIPTION然后从相应的目录中运行。该软件包安装得很好,并通过了所有检查。devtools::install()devtools::check()

于 2015-01-13T17:23:54.207 回答