lundi 29 février 2016

How to test for multiple warnings in an unknown order using testthat?

I want to test that a function generates multiple warnings (4 or more), when the order of the warnings can vary. My best attempt to do this is based on look-ahead RegExp matching. Simplifying to just 2 warnings, I know my RegExp work on a single string output, because both of the following are true:

grepl("(?s)(?=.*2)(?=.*1)", "* warn 1.\n* warn 2.", perl=TRUE)
grepl("(?s)(?=.*1)(?=.*2)", "* warn 1.\n* warn 2.", perl=TRUE)

However, this does not work when testing multiple warnings with testhat::expect_warning

# The function generating warnings:
foo <- function() { warning("warn 1."); warning("warn 2.") }
foo()
Warning messages:
1: In foo() : warn 1.
2: In foo() : warn 2.

# Testing it
expect_warning( foo(), "(?s)(?=.*1)(?=.*2)", perl=TRUE)

Error: foo() does not match '(?s)(?=.*1)(?=.*2)'. Actual values:
* warn 1.
* warn 2.

I suspect this is because the internals of expect_warning are doing something like testing the given RegExp against each warning separately--why an expect_warning( ... all=TRUE ) parameter might be meaningful.

Unfortunately I can't use this with a RegExp like "1 | 2"; that succeeds if only one warning is given.

I also want to avoid running the function multiple times and testing a different warning each time. There is a large amount of setup and teardown code needed to test the real function. It interacts heavily with the file system, and since it is the file-system warnings I am testing for, I can't mock that. Moreover, I want to test for the warnings in multiple situations, each of which requires different setup and teardown code, so this quickly bloats my tests.

Any suggestion on how to test for multiple warnings simply and all at once?

Aucun commentaire:

Enregistrer un commentaire