我想测试一个函数会在警告的顺序发生变化时生成多个警告(4个或更多)。我最好的尝试是基于前瞻RegExp匹配。简化为2个警告,我知道我的RegExp在单个字符串输出上工作,因为以下两个都是真的:
grepl("(?s)(?=.*2)(?=.*1)", "* warn 1.\n* warn 2.", perl=TRUE)
grepl("(?s)(?=.*2)(?=.*1)", "* warn 2.\n* warn 1.", perl=TRUE)
但是,使用testhat::expect_warning
# The function generating warnings:
foo <- function() { warning("warn 1."); warning("warn 2.") }
foo()
Warning messages:
1: In foo() : warn 1.
2: In foo() : warn 2.
# Testing it
expect_warning( foo(), "(?s)(?=.*1)(?=.*2)", perl=TRUE)
Error: foo() does not match '(?s)(?=.*1)(?=.*2)'. Actual values:
* warn 1.
* warn 2.
我怀疑这是因为expect_warning
的内部正在执行类似于针对每个警告单独测试给定的RegExp的事情 - 为什么expect_warning( ... all=TRUE )
参数可能有意义。
不幸的是,我不能像"1 | 2"
这样的RegExp使用它;如果只发出一个警告就会成功。
我还想避免多次运行该函数并每次都测试不同的警告。测试实际功能需要大量的设置和拆卸代码。它与文件系统进行了大量的交互,因为它是我正在测试的文件系统警告,我无法嘲笑它。此外,我想在多种情况下测试警告,每种情况都需要不同的设置和拆卸代码,因此这很快就会使我的测试失败。
有关如何简单地测试多个警告的任何建议吗?
答案 0 :(得分:2)
要捕获警告并手动分析它们,您还可以使用testthat::capture_warnings
:
# The function generating warnings:
foo <- function() { warning("warn 1."); warning("warn 2.") }
w <- capture_warnings(foo())
expect_match(w, ".*1", all = FALSE)
expect_match(w, ".*2", all = FALSE)
expect_match(w, ".*3", all = FALSE)
(最后一行引发错误。)
答案 1 :(得分:1)
所以我拼凑了一个解决方案,该解决方案涉及使用我自己的警告捕获循环并将警告检查为字符串。不是&#34;一下子&#34;解决方案,但鉴于复杂的函数调用,它至少是紧凑的。我将应用于示例函数foo()
的代码如下:
gotWarnings= character(0)
withCallingHandlers({
got <- foo()
}, warning= function(e) {
# Push warning onto vector in parent frame.
gotWarnings <<- c(gotWarnings, conditionMessage(e))
invokeRestart("muffleWarning")
})
# Ensure no unexpected warnings,
expect_equal(length(gotWarnings), 2)
# Test that each warning I want is there
expect_true( any( grepl( "warn 1\\.", gotWarnings )))
expect_true( any( grepl( "warn 2\\.", gotWarnings )))
了解如何在发出警告后继续处理是困难的部分;在发出第一个警告后,tryCatch
退出。 Here和here帮助我解决了这个问题。也许这可以转换为expect_all_warnings
测试,使得RegEx的向量匹配,可能与all= TRUE
意味着没有警告可以无法匹配。我推迟接受这个作为答案,以防有人发布更好的,或者至少有一个能很好地打包这样的解决方案。
答案 2 :(得分:0)
您可以使用[12]
之类的:
expect_warning( foo(),'(?s)(?=.*[12])' , all=T, perl=TRUE)