如何从基地模拟功能?

R Y*_*oda 12 r mocking testthat

我在我的代码中从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".
Run Code Online (Sandbox Code Playgroud)

?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"))
Run Code Online (Sandbox Code Playgroud)

导致testthat错误消息:

无法模拟基础包中的函数(基础)

编辑2:由于@suren在他的回答中显示我的代码示例在这里是错误的(模拟函数返回另一个类然后原始的:-(

正确的模拟函数应该是: Sys.info = function() return(c(sysname = "Clever OS"))

Sur*_*ren 6

错误消息是my.func()不等于"Clever OS"..原因是在模拟Sys.info函数a时返回命名的字符向量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)
  )
)
Run Code Online (Sandbox Code Playgroud)

这甚至可以在包中使用.

注意:基本功能的模拟不应该根据帮助而起作用,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)
          )
)
Run Code Online (Sandbox Code Playgroud)

或者,有一个列表中的字符串 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)
          )
)
Run Code Online (Sandbox Code Playgroud)