如何在R中编写包测试以查看是否正确抛出警告?

时间:2013-01-23 02:18:14

标签: r unit-testing package warnings

我正在为R软件包编写一些测试,并希望R CMD check验证函数是否显示某些输入的正确警告。但我无法弄清楚如何捕获警告输出,以便我可以测试它。

所以,如果我有这样的功能:

throwsWarning<-function(x){
  if(x>0){
    warning('Argument "x" is greater than zero, results may be incorrect')
  }
  # do something useful ...
}

我想在我的测试文件中添加一些内容,如:

warningOutput <-try( throwsWarning(1))
if (warningOutput!='Argument "x" is greater than zero, results may be incorrect'){
  stop('function "throwsWarning" did not produce correct warning when x>0')
}

到目前为止,我已经通过更改options找到了可能的部分解决方案,以便将警告视为错误,并将trycatch块视为周围环境。也考虑了last.warning的测试值,但如果没有抛出警告(将测试之前的值),这似乎很危险。似乎必须有一个简单的方法来做到这一点,我错过了?

2 个答案:

答案 0 :(得分:6)

testthat package有一个expect_warninggives_warning功能可以使用。

从示例中,您可以执行以下操作:

R> library(testthat)
R> expect_that(warning("this is a warning"), gives_warning("is a"))
## This does not raise an error, but:
R> expect_that(warning("this is a warning"), gives_warning("nope"))
Error: warning("this is a warning") does not match 'nope'. Actual value: 
this is a warning

因此,gives_warning是正则表达式,它与应该发出的警告相匹配。如果正则表达式不匹配(或者没有抛出警告),则会引发红色标记。

同样,使用较短的expect_warning

R> expect_warning(warning("this is a warning"), "is a")

答案 1 :(得分:2)

如果您正在编写自己的包,那么通过抛出(并捕获)特定类型的错误或警告来利用R的条件系统可能是有意义的。所以

myFun <- function(x) {
    if (any(is.na(x))) {
        w <- simpleWarning("'x' contains NA values")
        class(w) <- c("HasNA", class(w))
        warning(w)
    }
    if (any(x < 0))
        warning("'x' contains values less than 0")
    x
}

然后在您的测试中,例如,使用library(RUnit),使用tryCatch并选择您感兴趣的测试条件,即类HasNA的警告:< / p>

test_myFun_NAwarning <- function() {
    warnOccurred <- FALSE
    tryCatch(myFun(1:5), HasNA = function(w) warnOcccurred <<- TRUE)
    checkTrue(!warnOccurred)
    tryCatch(myFun(-(1:5)), HasNA = function(w) warnOcccurred <<- TRUE)
    checkTrue(!warnOccurred)
    tryCatch(myFun(c(1:5, NA)), HasNA = function(w) warnOccurred <<- TRUE)
    checkTrue(warnOccurred)
}

导致

> test_myFun_NAwarning()
[1] TRUE
Warning message:
In myFun(-(1:5)) : 'x' contains values less than 0

表明tryCatch只捕获您感兴趣的特定警告,并且这样做的方式不依赖于匹配字符串的文本。也许你有一个辅助函数.warn来为你的包发出所有警告。有关其他详细信息,请参阅?withCallingHandlers; withCallingHandlersmuffleRestart是警告发生后如何处理持续评估,而不是停止tryCatch的方式。