首页 > 解决方案 > 环境问题使用 testthat

问题描述

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

我使用evalandmatch.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(ie parent.frame()) 使用的默认环境,但我不知道该怎么做。

标签: rtestthatnse

解决方案


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

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 <- function(a, b) {
  helper(mget(ls()))
}
helper <- function(params) {
  do.call("main", params)
}

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


推荐阅读