使用testthat的环境问题

Environmental problems using testthat

我有一些微妙的环境问题,这些问题目前在我的单元测试中表现出来。我的基本结构是这样

我使用 evalmatch.call() 在包装器和主函数之间顺利移动。 我现在的问题是,当我逐行 运行 但不使用 test_that().

时,我的测试工作正常

这是一个显示问题的 MWE。如果您手动单步执行测试中的行,则测试会通过。但是,评估整个 test_that() 块测试失败,因为无法找到其中一个参数。

library(testthat)

wrapper <- function(a, b) {
  fun_call <- as.list(match.call())
  ret <- helper(fun_call)
  return(ret)
}

helper <- function(fun_call) {
  fun_call[[1]] <- quote(main)
  fun_call <- as.call(fun_call)
  fun_eval <- eval(as.call(fun_call))
  return(fun_eval)
}

main <- function(a, b, c = 1) {
  ret <- list(a = a, b = b, c = c)
  return(ret)
}

test_that("Test", {
  a <- 1
  b <- 2
  x <- wrapper(a = a, b = b)
  y <- list(a = 1, b = 2, c = 1)
  expect_equal(x, y)
})

我很有信心地怀疑我需要修改 eval 使用的默认环境(即 parent.frame()),但我不确定该怎么做。

您想在父环境而不是本地函数环境中评估您的调用。将您的助手更改为

helper <- function(fun_call) {
  fun_call[[1]] <- quote(main)
  fun_call <- as.call(fun_call)
  fun_eval <- eval.parent(fun_call, n=2)
  return(fun_eval)
}

这是假设 helper 总是在 wrapper 中调用,而 wrapper 是从其他地方调用的,参数已定义。

在这种情况下并不清楚您是否真的需要所有这些非标准的评估。您也可以考虑

这样的解决方案
wrapper <- function(a, b) {
  helper(mget(ls()))
}
helper <- function(params) {
  do.call("main", params)
}

此处wrapper只是将其所有参数值捆绑到一个列表中。然后你可以只传递一个参数列表给 helper 并且 do.call 会将该列表作为参数传递给你的 main 函数。这将在您调用它时评估 wrapper 的参数,您不必担心执行环境。