我在代码中调用base函数,我想在testthat
单元测试中模拟这个函数。
我该怎么做?
library(testthat)
my.func <- function() {
return(Sys.info()["sysname"]) # e. g. "Linux"
}
my.func()
# sysname
# "Linux"
test_that("base function can be mocked",
with_mock(
Sys.info = function() return(list(sysname = "Clever OS")), # see edit 2 !!!
expect_equal(my.func(), "Clever OS", fixed = TRUE)
)
)
# Error: Test failed: 'base function can be mocked'
# * my.func() not equal to "Clever OS".
?with_mock
说:
无法模拟基础包中的函数,但这可以起作用 通过定义包装函数轻松实现。
我可以通过我从Sys.info()
调用的包装函数将基函数调用封装到my.func
然后让我们假设我不能这样做,因为我正在测试一个我无法更改的包中的函数...
对此有何解决方案?
我在Ubuntu 14.04上使用R3.4.4 64位,testthat为2.0.0.9000。
修改1:
使用
`base::Sys.info` = function() return(list(sysname = "Clever OS"))
导致testthat
错误消息:
无法在基础包(基础)中模拟函数
编辑2:由于@suren在他的回答中显示我的代码示例在这里是错误的(模拟函数返回另一个类然后是原始类: - (
正确的模拟函数应该是:Sys.info = function() return(c(sysname = "Clever OS"))
答案 0 :(得分:6)
错误消息 my.func()不等于“Clever OS”。。
原因是Sys.info
返回一个命名的字符向量,而模拟函数为list
。
只需修改模拟函数和期望值即可:
test_that("base function can be mocked",
with_mock(
Sys.info = function() return(c(sysname = "Clever OS")),
expect_equal(my.func(), c(sysname = "Clever OS"), fixed = TRUE)
)
)
这甚至可以在包中使用。
注意:根据with_mock
的帮助,基本功能的模拟不应该起作用,但它确实(至少在目前)。
以下(my.func()$`sysname`)似乎使用问题中的原始代码传递测试。
test_that("base function can be mocked",
with_mock(
Sys.info = function() return(list(sysname = "Clever OS")),
expect_equal(my.func()$`sysname`, "Clever OS", fixed = TRUE)
)
)
或者,列出expect_equal
test_that("base function can be mocked",
with_mock(
Sys.info = function() return(list(sysname = "Clever OS")),
expect_equal(my.func(), list(`sysname` = "Clever OS"), fixed = TRUE)
)
)
答案 1 :(得分:3)
关于使用with_mock
模拟基本函数的警告:
即使基本函数的模拟可能在我的问题和@Suren的接受答案中有效,但with_mock
包中testthat
的许多问题都不鼓励模拟基本包函数(甚至是外部函数)被测试的包裹),e。克。
testthat 2.0.0 - Breaking API changes
mockery
或mockr
。 Don't allow base packages to be mocked
with_mock() function seems to interact badly with the JIT compiler