How to write a test package in R to see if a warning is selected correctly?

I am writing several tests for the R package and would like to have an R CMD check to verify that the functions display the correct warnings for certain inputs. But I can’t understand how to write the output of the warning so that I can test it.

So, if I have a function like:

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

I need something in my test file, for example:

 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') } 

So far, I have found possible partial solutions by changing options so that warnings are handled as errors and surrounding using the trycatch block. The test value last.warning is also considered, but it seems dangerous if a warning is not selected (it will check the previous value). It seems like there should be an easy way to do this so that I go missing?

+6
source share
2 answers

The test package has expect_warning and gives_warning , which you can use.

From the examples you would do something like this:

 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 

So gives_warning is a regular expression that matches the warning that should be selected. If the regular expression does not match (or a warning is not issued), then a red flag appears.

Similarly, using the shorter expect_warning :

 R> expect_warning(warning("this is a warning"), "is a") 
+6
source

If you are writing your own package, it might make sense to use the R state system by throwing (and catching) certain types of errors or warnings. So

 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 } 

and then in your test, for example, using library(RUnit) , use tryCatch and select only those conditions that interest you when testing, i.e. warnings with HasNA class:

 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) } 

leading to

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

which shows that tryCatch captures only the specific warning that interests you, and does so in a way that does not rely on line text matching. Perhaps you have a helper function .warn to do all the warnings for your package. See ?withCallingHandlers ; withCallingHandlers and muffleRestart is how you can handle a constant evaluation after a warning occurs, rather than stopping on the tryCatch path.

+2
source

All Articles