如何用testthat::expect_warning()正确测试函数的多个预期警告?
解决testthat测试多个警告的问题
你的问题核心是:每次测试单个警告时,函数抛出的另一个警告会被额外输出,虽然测试通过,但输出冗余。以下是两种正确的解决方式:
方法一:使用expect_warnings捕获并验证所有警告(推荐)
testthat 3.0.0及以上版本提供了expect_warnings函数,可一次性捕获所有警告,再分别验证每个警告的内容,同时不会输出未匹配的警告。
修改后的测试代码:
test_that("f1 works correctly with warnings", { # 测试正常功能 expect_equal(f1(2), -2) expect_equal(f1(-1), -1) # 测试正数输入无警告 expect_warning(f1(1), NA) # 捕获所有警告并验证数量和内容 captured_warnings <- expect_warnings(f1(-1), n = 2) expect_match(captured_warnings[1], "already negative") expect_match(captured_warnings[2], "second warning") })
说明:
expect_warnings(f1(-1), n = 2)确保函数恰好抛出2个警告,同时返回这两个警告的文本向量。- 后续用
expect_match分别验证每个警告的内容,完全覆盖预期的警告信息。
方法二:用正则表达式匹配所有警告
如果无法升级testthat版本,可在单个expect_warning中用正则表达式匹配所有警告的组合,同时避免冗余输出:
test_that("f1 works correctly with warnings", { # 测试正常功能 expect_equal(f1(2), -2) expect_equal(f1(-1), -1) # 测试正数输入无警告 expect_warning(f1(1), NA) # 精确匹配两个警告的完整序列(包含换行符) expect_warning( f1(-1), "^\\*x\\* is already negative\nthis is a second warning$", fixed = TRUE ) # 或分别匹配单个警告,抑制冗余输出 expect_warning(f1(-1), "already negative", all = FALSE) expect_warning(f1(-1), "second warning", all = FALSE) })
说明:
- 第一种正则写法用
fixed = TRUE精确匹配两个警告的完整文本,确保所有预期警告都被覆盖。 - 第二种写法通过
all = FALSE告知testthat只需匹配指定警告即可,不会因存在其他警告报错,同时减少冗余输出。
原代码出现冗余警告的原因
原代码中每次调用f1(-1)都会抛出两个警告,而expect_warning默认仅检查是否存在匹配的警告,未被匹配的警告会被R的警告机制直接输出。expect_warnings则会捕获所有警告,不会让未匹配的警告泄露到输出中。
内容的提问来源于stack exchange,提问作者VinceGreg
相关产品推荐
相关产品推荐

