我有一个这样的功能:
func <- function(x) {
if (requireNamespace("broom", quietly = TRUE)) {
print(1)
} else {
print(2)
}
我想使用
testthat
编写测试来触发 both 情况。当然,我的计算机上要么安装了,要么没有安装。 该怎么办?:从 broom
开始,此功能不再有效。根据 2017 年 10 月的变更
:“无法模拟基础包中的函数”:您不能再使用
。testthat-2.0.0
来模拟基础包中的函数,因为由于字节码编译器的更改,这在 R-devel 中不再起作用。我建议使用
- mockery
其余答案仅适用于旧版本的或mockr 代替。with_mock()
testthat
testthat::with_mock
一些简单的测试:library(testthat)
somefunc <- function() if (requireNamespace("base", quietly=TRUE)) 1L else 2L
成功了。
expect_equal( somefunc(), 1L )
预计。
让我们创建一个覆盖基本函数的“模拟”函数:
expect_equal( somefunc(), 2L )
# Error: somefunc() not equal to 2.
# 1/1 mismatches
# [1] 1 - 2 == -1
注意:成功时,
with_mock(
`base::requireNamespace` = function(package, ..., quietly=FALSE) FALSE,
expect_equal( somefunc(), 1L )
)
# Error: somefunc() not equal to 1.
# 1/1 mismatches
# [1] 2 - 1 == 1
with_mock(
`base::requireNamespace` = function(package, ..., quietly=FALSE) FALSE,
expect_equal( somefunc(), 2L )
)
# [1] 2
会无形地返回返回值,因此在第一个示例中您看不到expect_equal
。
[1] 1
,成功时返回返回值,但不是隐形的。在这两种情况下,失败都会返回修改后的返回值。这一微小的差异不应影响任何测试。
根据您要重写的函数,(对我来说)小心地使用相同的形式定义模拟函数是有意义的。如果您在测试期间确切地知道它是如何
总是在所有从属函数中调用的,您也许可以走捷径,但我认为对形式的额外仔细关注将排除真正难以解决的测试失败. 注意:帮助说明了这一点
...仍处于实验阶段,因此请小心使用。
with_mock
这是适用于较新版本的 withr 的解决方案:
old_fn <- base::requireNamespace
myrequireNamespace <- function(...) FALSE
unlockBinding("requireNamespace", as.environment("package:base"))
assign("requireNamespace",myrequireNamespace, "package:base")
expect_error(read_data("meta",data_table, frame=NULL),"Package \"readxl\"
needed for this function to load excel files")
assign("requireNamespace",old_fn, "package:base")
lockBinding("requireNamespace", as.environment("package:base"))
rm(old_fn, myrequireNamespace)