testthat是否存在对比两个对象行为的expect_*系列函数?
testthat函数等价性断言相关解答
- 截至最新的testthat 3.2.x版本,官方没有内置
expect_equal_applied这类支持传入函数列表的批量等价断言函数。
该模式没有被纳入官方API的核心原因是testthat的设计更偏向单断言单校验原则:单个断言仅验证一项逻辑,测试失败时可以直接定位到具体的校验点,也方便为每个校验点单独配置提示信息、容错阈值等参数。如果把多个校验逻辑打包到单个断言中,会提升测试失败后的定位成本,也会降低测试用例的可读性。
如果需要简化重复的同类断言,R包开发社区有两种被广泛使用的惯用实现方式:
方式1:借助循环直接实现(最常用)
用purrr循环或者基础循环批量执行断言,代码简洁同时保留原生的错误定位能力:
library(testthat) library(purrr) x <- 1:4 y <- matrix(4:1, nrow=2) test_that("objects behave similarly", { # 给函数命名可以让报错信息更清晰 target_fns <- list(sum = sum, prod = prod) walk(target_fns, \(fn) expect_equal(fn(x), fn(y))) })
方式2:自定义断言函数
如果需要大量复用该逻辑,可以按照testthat的扩展规范自定义断言函数,自定义的断言函数完全兼容testthat的测试报告体系:
expect_equal_applied <- function(object, expected, .fn, ...) { stopifnot(is.list(.fn)) # 为匿名函数自动生成名称,方便报错定位 if (is.null(names(.fn))) { names(.fn) <- paste0("function_", seq_along(.fn)) } obj_nm <- deparse1(substitute(object)) exp_nm <- deparse1(substitute(expected)) for (fn_nm in names(.fn)) { fn <- .fn[[fn_nm]] expect_equal( fn(object), fn(expected), ..., label = paste0(fn_nm, "(", obj_nm, ")"), expected.label = paste0(fn_nm, "(", exp_nm, ")") ) } }
自定义完成后即可直接使用你示例中的写法:
test_that("objects behave similarly", { expect_equal_applied(x, y, .fn = list(sum, prod)) })
内容的提问来源于stack exchange,提问作者merv
相关产品推荐
相关产品推荐

