使用map时test_that首次失败即终止的问题及解决办法咨询
问题分析与解决方法
原因
确实和testthat的版本更新有关。在testthat 3.0.0及之后的版本中,官方调整了单个test_that()块内的错误处理逻辑:一旦某个expect_*断言失败,会立即抛出错误并终止当前test_that块的执行,不再继续运行后续代码。这和旧版本中允许在同一test_that块内完成所有迭代、汇总所有失败结果的行为不同,本质是testthat对测试用例独立性的强化,而非单纯reporter的变化。
解决方法
方法1:拆分独立测试用例(推荐)
将每个参数对应的测试拆分为单独的test_that()块,这样每个测试都是独立的单元,不会因某一个失败而中断其他测试的执行。用purrr::walk()可以快速生成这些测试:
Parameters <- c(1, 2, 3, 4, 5) purrr::walk(Parameters, function(param) { test_that(sprintf("验证参数值等于2:param = %d", param), { expect_equal(param, 2) }) })
执行后会得到5个独立的测试结果,其中4次失败、1次通过,和你之前预期的行为一致。
方法2:在单个测试块内捕获错误
如果必须在同一个test_that()块内完成所有迭代,可以用purrr::safely()包裹测试函数,捕获每个迭代的错误,避免单个失败终止整个流程,最后手动汇总结果:
test_that("批量验证参数值等于2", { Parameters <- c(1, 2, 3, 4, 5) test_map <- function(Parameter) { expect_equal(Parameter, 2) } # 捕获每个测试的执行结果(成功返回结果,失败返回错误信息) test_results <- purrr::map(Parameters, purrr::safely(test_map)) # 筛选出所有失败的测试 failed_tests <- purrr::keep(test_results, ~ !is.null(.x$error)) # 如果有失败,抛出汇总错误 if (length(failed_tests) > 0) { fail(sprintf("共 %d 个测试失败", length(failed_tests))) } })
这种方式会在所有迭代完成后,一次性报告失败数量,但不会展示每个失败的具体细节,适合只需要汇总结果的场景。
方法3:全局禁用单块测试终止(不推荐)
可以通过设置全局选项,让test_that()块遇到失败时不立即终止:
options(testthat.stop_on_failure = FALSE)
但这个设置会影响所有测试用例,可能导致单个测试块内的错误堆积,不利于快速定位问题,因此不建议在正式测试流程中使用。
内容的提问来源于stack exchange,提问作者Paul Eagle
相关产品推荐
相关产品推荐

