Search code examples
rwarningsassigntestthat

Capture warnings and assign a value in one go?


I am running some unit tests using the testthat package. I have a function that is tested repeatedly under various conditions. My problem is that the function has three kinds of "outputs":

  1. Prints to the console. This should be discarded.
  2. Elicits a warning sometimes. The test should pass on a particular warning, but fail for others.
  3. Returns a value. I want to save that for further testing.

Is there a way to do this? I cannot change the function in question as it ships with another package.

Here is a simple repex:

func = function() {
  print("a print")
  warning("a warning")
  return("a value")
}

I can accomplish (1) and (3) by doing

capture.output(result <<- func())
# result can be tested here, but the warning is not captured

I can do (1) and (2) by doing

msg = testthat::capture_warning(capture.output(result <<- func()))
if (!is.null(msg$message)) {
   testthat::expect_true(msg$message == "a warning")
}
# result is undefined here

Again, is there a way to achieve all three goals above?


Solution

  • with quietly from the purrr package you can capture warnings, prints, messages, output while still returning a value.

    Then, you may build a wrapping function around that to develop your checks and your conditions.

    func <- function() {
      print("a print")
      warning("a warning")
      return("a value")
    }
    
    library(purrr)
    
    res <- quietly(func)()
    res
    
    # $result
    # [1] "a value"
    #
    # $output
    # [1] "[1] \"a print\""
    #
    # $warnings
    # [1] "a warning"
    #
    # $messages
    # character(0)
    
    

    quietly is a sort of function decorator.