You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在R中如何使用withr::defer()替代已弃用的testthat::setup()?

testthat v3 替代旧版setup()的实现方案

针对你需要在单个测试文件内仅执行一次耗时数据生成、供所有测试用例复用的需求,搭配withr::defer的实现方式如下,可完全对齐旧版setup()的使用效果:

代码实现

直接在测试文件的最外层作用域编写生成逻辑即可:

# 测试文件开头,该逻辑仅会在当前文件加载时执行1次
data <- matrix(rnorm(9), 3, 3)

# 如果需要实现原teardown()的资源清理效果(比如关闭数据库连接、删除临时文件),再搭配withr::defer使用
# withr::defer({
#   # 此处写资源释放逻辑
#   rm(data)
#   dbDisconnect(conn)
# }, envir = testthat::get_test_file_env())

后续测试用例无需额外修改,直接使用预生成的data对象即可:

# 第一个测试
test_that("校验数据行数量", {
    expect_equal(nrow(data), 3)
})

# 第二个测试
test_that("校验数据列数量", {
    expect_equal(ncol(data), 3)
})

原理解释

  • testthat v3中单个测试文件的所有代码会在独立的文件环境中运行,test_that块外定义的变量默认对当前文件所有测试用例可见,且仅执行一次,原生匹配旧版setup()的核心需求。
  • 仅当你需要在当前文件所有测试执行完毕后自动释放资源时,才需要调用withr::defer,指定环境参数为当前测试文件的环境,清理逻辑就会在全文件测试结束后自动触发。
  • 若你只需要复用固定测试数据、无后续清理需求,甚至不需要显式调用withr::defer,直接在测试文件外层生成数据即可。

单测试用例独立生成数据的场景

如果后续有需求要求每个测试用例拿到互不干扰的全新数据,可以封装为固件函数:

# 定义可复用的测试数据固件
create_test_data <- function() {
  data <- matrix(rnorm(9), 3, 3)
  # 绑定清理逻辑到调用测试用例的环境,用例跑完自动清理
  withr::defer(rm(data), envir = parent.frame())
  return(data)
}

test_that("校验数据行数量", {
  data <- create_test_data()
  expect_equal(nrow(data), 3)
})

test_that("校验数据列数量", {
  data <- create_test_data()
  expect_equal(ncol(data), 3)
})

该写法下每个测试用例都会重新执行一次数据生成逻辑,完全避免用例之间的状态干扰。

内容的提问来源于stack exchange,提问作者Mihai Constantin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.15 01:45:04