使用testthat的环境问题
Environmental problems using testthat
我有一些微妙的环境问题,这些问题目前在我的单元测试中表现出来。我的基本结构是这样
- 我有一个有很多参数的主函数
main
wrapper
是一个包装函数(许多函数之一),仅适用于 main
的选定参数
helper
是一个中间辅助函数,被所有包装函数使用
我使用 eval
和 match.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
的参数,您不必担心执行环境。
我有一些微妙的环境问题,这些问题目前在我的单元测试中表现出来。我的基本结构是这样
- 我有一个有很多参数的主函数
main
wrapper
是一个包装函数(许多函数之一),仅适用于main
的选定参数
helper
是一个中间辅助函数,被所有包装函数使用
我使用 eval
和 match.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
的参数,您不必担心执行环境。