如何对R包中符合指定命名规则的函数批量执行testthat测试
批量测试R包内指定命名规则函数的可靠方案
原代码R CMD check运行失败的核心原因
- R CMD check的测试环境中,你的包不会默认加载到
search()路径的顶层,直接调用ls("package:mypackage")会抛出找不到包环境的错误 - 字符串拼接+
eval()的调用方式会触发R CMD check的可疑代码检查,同时存在安全隐患 - 没有错误捕获逻辑,一旦某一个函数调用失败,无法直接定位问题函数
可通过R CMD check的实现方案
假设你的所有viz_*函数无参数即可正常运行,如果部分函数需要必填入参,可以参考后续的扩展适配方案。
testthat::test_that("所有viz_开头函数返回gg类对象", { # 替换为你的实际包名 pkg_name <- "mypackage" # 直接获取包命名空间,不依赖search路径加载状态 pkg_ns <- asNamespace(pkg_name) # 匹配所有viz_开头的导出对象,过滤出函数 viz_func_names <- ls(pkg_ns, pattern = "^viz_") viz_funcs <- Filter(function(name) is.function(pkg_ns[[name]]), viz_func_names) # 遍历测试每个函数 for (func_name in viz_funcs) { # 从命名空间安全获取函数 target_func <- getExportedValue(pkg_name, func_name) # 调用函数并捕获错误,方便定位问题 plt <- tryCatch( suppressMessages(suppressWarnings(target_func())), error = function(e) { stop(sprintf("函数%s调用失败:%s", func_name, e$message)) } ) # 类型检查,附带函数名提示,失败时可直接定位问题 testthat::expect_s3_class(plt, "gg", info = sprintf("当前测试函数:%s", func_name)) } })
扩展适配:处理带必填参数的函数
如果部分viz_*函数需要传入必填参数,可以提前定义参数映射列表,调用时使用do.call传参:
# 定义空值合并操作符,也可以直接使用rlang::`%||%` `%||%` <- function(x, y) if (is.null(x)) y else x testthat::test_that("所有viz_开头函数返回gg类对象", { pkg_name <- "mypackage" pkg_ns <- asNamespace(pkg_name) viz_func_names <- ls(pkg_ns, pattern = "^viz_") viz_funcs <- Filter(function(name) is.function(pkg_ns[[name]]), viz_func_names) # 预定义各函数的入参列表,无参数的函数可以不写 func_param_map <- list( viz_foo = list(data = test_dataset, x = "date", y = "value"), viz_bar = list(group_col = "category", fill = "#2c3e50") ) for (func_name in viz_funcs) { target_func <- getExportedValue(pkg_name, func_name) params <- func_param_map[[func_name]] %||% list() plt <- tryCatch( suppressMessages(suppressWarnings(do.call(target_func, params))), error = function(e) { stop(sprintf("函数%s调用失败:%s", func_name, e$message)) } ) testthat::expect_s3_class(plt, "gg", info = sprintf("当前测试函数:%s", func_name)) } })
内容的提问来源于stack exchange,提问作者Matt Cowgill
相关产品推荐
相关产品推荐

