9

当警告的顺序可能不同时,我想测试一个函数是否会生成多个警告(4 个或更多)。我最好的尝试是基于前瞻正则表达式匹配。简化为只有 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 )参数可能是有意义的。

不幸的是,我不能将它与 RegExp 等一起使用"1 | 2";如果只给出一个警告就成功了。

我还想避免多次运行该函数并每次测试不同的警告。测试真正的功能需要大量的设置和拆卸代码。它与文件系统进行大量交互,并且因为它是我正在测试的文件系统警告,所以我不能模拟它。此外,我想在多种情况下测试警告,每种情况都需要不同的设置和拆卸代码,所以这很快就会使我的测试膨胀。

关于如何一次简单地测试多个警告的任何建议?

4

3 回答 3

6

要捕获警告并“手动”分析它们,您还可以使用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)

(最后一行引发错误。)

于 2017-07-21T09:11:25.120 回答
2

所以我拼凑了一个解决方案,其中涉及使用我自己的警告捕获循环并将警告作为字符串检查。不是“一次性”解决方案,但考虑到复杂的函数调用,它至少是紧凑的。我的代码将应用于示例函数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收到第一个警告后退出。这里这里帮助我解决了这个问题。也许这可以转换为一个expect_all_warnings测试,它需要一个正则表达式的向量来匹配,也许all= TRUE意味着没有警告可以不匹配。我会推迟接受这个作为答案,以防有人发布更好的答案,或者至少发布一个很好地打包这样的解决方案的答案。

于 2016-03-01T18:01:10.100 回答
0

你也许可以使用[12]类似的东西:

expect_warning( foo(),'(?s)(?=.*[12])' , all=T, perl=TRUE)
于 2016-03-01T00:48:23.510 回答