6

我正在为 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,但如果不抛出警告,这似乎很危险(将测试以前的值)。似乎必须有一个简单的方法来做到这一点,我错过了?

4

2 回答 2

6

testthat有一个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")
于 2013-01-23T02:58:36.827 回答
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并选择您对测试感兴趣的条件,即带有 class 的警告HasNA

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来为你的包发出所有警告。更多细节参见?withCallingHandlerswithCallingHandlers以及muffleRestart人们如何应对警告发生后的持续评估,而不是停止这种方式tryCatch

于 2013-01-23T21:31:38.673 回答