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

R包测试中使用testthat跨单元测试复用变量避免重复生成高开销对象

R包testthat测试中复用高开销生成对象的规范方案

下面是两种符合testthat开发规范的实现方案,均可以避免提前调用未完成测试的函数,同时减少重复生成对象的时间开销:

方案1:按测试文件顺序执行+运行时缓存

testthat默认按文件名字典顺序执行测试文件,你可以通过命名控制测试执行优先级,仅在create_obj测试完全通过后再缓存对象:

  • 重命名测试文件,保证create_obj的测试先执行:
    • create_obj的测试文件命名为test-01-create_obj.R
    • plot_obj的测试文件命名为test-02-plot_obj.R
  • 在test-01-create_obj.R中完成所有测试后缓存对象:
test_that("create_obj功能正常", {
  objA <- create_obj(sample)
  expect_equal(length(objA), 10)
  # 其他create_obj测试逻辑

  # 所有测试通过后,缓存对象到testthat共享测试环境
  test_env <- getOption("testthat_env")
  test_env$cached_objA <- objA
  # 并行测试场景可改用临时文件存储
  # saveRDS(objA, file.path(tempdir(), "cached_objA.RDS"))
})
  • 在test-02-plot_obj.R中直接读取缓存对象使用:
test_that("plot_obj生成正确绘图", {
  # 读取缓存对象
  objA <- getOption("testthat_env")$cached_objA
  # 并行场景读临时文件
  # objA <- readRDS(file.path(tempdir(), "cached_objA.RDS"))
  
  # 你的plot_obj测试逻辑,例如用vdiffr校验绘图输出
  vdiffr::expect_doppelganger("objA默认绘图", plot_obj(objA))
})

方案2:使用fixture封装缓存逻辑(适合testthat 3.0+版本)

你可以将对象生成+合法性校验逻辑封装为可复用的fixture,仅在第一次被调用时执行生成和测试逻辑,后续所有测试调用直接复用缓存对象:

  • 在tests/testthat/setup.R中定义fixture:
fixture_objA <- function() {
  # 已生成过则直接返回缓存,避免重复执行
  if (exists("cached_objA", envir = .GlobalEnv)) {
    return(.GlobalEnv$cached_objA)
  }
  # 生成对象并完成内置校验
  objA <- create_obj(sample)
  expect_equal(length(objA), 10)
  # 其他create_obj校验逻辑

  # 缓存到全局环境
  assign("cached_objA", objA, envir = .GlobalEnv)
  return(objA)
}
  • 所有需要用到objA的测试直接调用fixture即可:
# 任意测试文件中调用
test_that("plot_obj功能正常", {
  objA <- fixture_objA()
  expect_s3_class(plot_obj(objA), "ggplot")
})

注意事项

  • 并行测试场景下不要使用全局环境缓存,改用临时目录存储RDS文件的方式,避免多进程读写冲突。
  • testthat测试会话结束后会自动清理临时目录和测试环境,不会有缓存残留影响后续测试的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 22:42:03