如何使用testthat测试未知顺序中的多个警告?

时间:2016-03-01 00:34:22

标签: regex r unit-testing testthat

我想测试一个函数会在警告的顺序发生变化时生成多个警告(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使用它;如果只发出一个警告就会成功。

我还想避免多次运行该函数并每次都测试不同的警告。测试实际功能需要大量的设置和拆卸代码。它与文件系统进行了大量的交互,因为它是我正在测试的文件系统警告,我无法嘲笑它。此外,我想在多种情况下测试警告,每种情况都需要不同的设置和拆卸代码,因此这很快就会使我的测试失败。

有关如何简单地测试多个警告的任何建议吗?

3 个答案:

答案 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退出。 Herehere帮助我解决了这个问题。也许这可以转换为expect_all_warnings测试,使得RegEx的向量匹配,可能与all= TRUE意味着没有警告可以无法匹配。我推迟接受这个作为答案,以防有人发布更好的,或者至少有一个能很好地打包这样的解决方案。

答案 2 :(得分:0)

您可以使用[12]之类的:

expect_warning( foo(),'(?s)(?=.*[12])' , all=T, perl=TRUE)