How to mute messages and warnings with testthat when they are expected
Asked Answered
C

2

2

In order to develop a package, I am using testthat. I want to test if my functions send proper messages and warnings. I want to test the results of functions at the same time. This is how I am trying to do it:

## R/foo.r
foo <- function() {
  message("This is a message")
  warning("This is a warning")
  "This is a result"
}

I write these tests:

## tests/testthat/test-foo.R

test_that("foo works", {
  expect_equal(foo(), "This is a result")
  expect_message(foo(), "This is a message")
  expect_warning(foo(), "This is a warning")
})

But now when I run the tests I have this:

Loading testWarnMess
Testing testWarnMess
v |  OK F W S | Context
/ |   0       | foo                                                                           This is a message
v |   3   2   | foo [0.3 s]                                                                   
----------------------------------------------------------------------------------------------
Warning (test-foo.R:2:3): foo works
This is a warning
Backtrace:
 1. testthat::expect_equal(foo(), "This is a result") test-foo.R:2:2
 4. testWarnMess::foo()

Warning (test-foo.R:3:3): foo works
This is a warning
Backtrace:
 1. testthat::expect_message(foo(), "This is a message") test-foo.R:3:2
 7. testWarnMess::foo()
----------------------------------------------------------------------------------------------

== Results ===================================================================================
Duration: 0.3 s

[ FAIL 0 | WARN 2 | SKIP 0 | PASS 3 ]
This is a message

How to prevent messages and warnings to be seen in the test results when I am expecting them to happen?

Cheeseparing answered 9/3, 2021 at 13:36 Comment(0)
C
2

One great way to do that is to use the adverb purrr::quietly.

test_that("foo works", {
  qfoo <- purrr::quietly(foo)
  qfoo_call <- qfoo()
  expect_equal(qfoo_call$result, "This is a result")
  expect_equal(qfoo_call$message, "This is a message")
  expect_equal(qfoo_call$warning, "This is a warning")
})

Cheeseparing answered 19/3, 2021 at 21:6 Comment(0)
C
3

The documentation for expect_warning() and expect_message() states:

In the 3rd edition, these functions match (at most) a single condition. All additional and non-matching (if regexp or class are used) conditions will bubble up outside the expectation. If these additional conditions are important you'll need to catch them with additional expect_message()/expect_warning() calls; if they're unimportant you can ignore with suppressMessages()/suppressWarnings().

So there should be no need to bloat your package with dependencies. Here's one way to do it:

test_that("foo works", {
  expect_warning(
    expect_message(foo(), "This is a message"),
    "This is a warning"
  )
  expect_equal(
    suppressWarnings(suppressMessages(foo())),
    "This is a result"
  )
})

If your case is much more complex than this, you may prefer to use expect_snapshot() instead.

China answered 17/10, 2023 at 11:33 Comment(2)
Very interesting (upvoted) but not sure this is a better call. For two reasons: (1) Decrease readability, (2) foo need to be called twice. From the dependency point of view, is it possible to use a package in the test part that is not required to be part of the dependcies of the final produced package?Cheeseparing
IIRC, if you're using a package just on tests and vignettes (also examples, according to the docs), you could list it under "Suggests" so it's like a soft dependency.China
C
2

One great way to do that is to use the adverb purrr::quietly.

test_that("foo works", {
  qfoo <- purrr::quietly(foo)
  qfoo_call <- qfoo()
  expect_equal(qfoo_call$result, "This is a result")
  expect_equal(qfoo_call$message, "This is a message")
  expect_equal(qfoo_call$warning, "This is a warning")
})

Cheeseparing answered 19/3, 2021 at 21:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.