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

如何用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 12:17:45