如何测试依赖于是否安装软件包的行为

问题描述 投票:0回答:3

我有一个这样的功能:

func <- function(x) {
  if (requireNamespace("broom", quietly = TRUE)) {

    print(1)

  } else {

    print(2)

  }

我想使用

testthat
编写测试来触发 both 情况。当然,我的计算机上要么安装了,要么没有安装。 该怎么办?
    

r testthat
3个回答
6
投票
编辑

:从 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

1
投票
对我来说是一种解决方法,它确实在 testthat 内部起作用。
    

这是适用于较新版本的 withr 的解决方案:

0
投票
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)


© www.soinside.com 2019 - 2024. All rights reserved.