2

I'd like to test that one of my functions gives a particular message (or warning, or error).

good <- function() message("Hello")
bad <- function() message("Hello!!!!!")

I'd like the first expectation to succeed and the second to fail.

library(testthat)
expect_message(good(), "Hello", fixed=TRUE)
expect_message(bad(), "Hello", fixed=TRUE)

Unfortunately, both of them pass at the moment.

For clarification: this is meant to be a minimal example, rather than the exact messages I'm testing against. If possible I'd like to avoid adding complexity (and probably errors) to my test scripts by needing to come up with an appropriate regex for every new message I want to test.

pete
  • 2,327
  • 2
  • 15
  • 23

2 Answers2

7

You can use ^ and $ anchors to indicate that that the string must begin and end with your pattern.

expect_message(good(), "^Hello\\n$")
expect_message(bad(), "^Hello\\n$")
#Error: bad() does not match '^Hello\n$'. Actual value: "Hello!!!!!\n"

The \\n is needed to match the new line that message adds.

For warnings it's a little simpler, since there's no newline:

expect_warning(warning("Hello"), "^Hello$")

For errors it's a little harder:

good_stop <- function() stop("Hello")
expect_error(good_stop(), "^Error in good_stop\\(\\) : Hello\n$")

Note that any regex metacharacters, i.e. . \ | ( ) [ { ^ $ * + ?, will need to be escaped.


Alternatively, borrowing from Mr. Flick's answer here, you could convert the message into a string and then use expect_true, expect_identical, etc.

messageToText <- function(expr) {
  con <- textConnection("messages", "w")
  sink(con, type="message")
  eval(expr)
  sink(NULL, type="message")
  close(con)
  messages
}

expect_identical(messageToText(good()), "Hello")
expect_identical(messageToText(bad()), "Hello") 
#Error: messageToText(bad()) is not identical to "Hello". Differences: 1 string mismatch
Community
  • 1
  • 1
GSee
  • 48,880
  • 13
  • 125
  • 145
  • Thanks. I'll add the requirements to match errors and warnings then accept. – pete Jun 29 '14 at 22:06
  • @pete I didn't realize errors were part of the requirement, but I probably wouldn't do it the way you edited into my answer. What about this? `bad_stop <- function() stop("Hello", call.=FALSE)` Do you want that to fail the test? – GSee Jun 30 '14 at 00:00
  • I'm not sure if that one ought to fail or not, and I guess I'd prefer to have the option? I guess I could use `^Error (|in good_stop\\(\\) ): Hello\n$` but that's getting messy. I might just end up making a feature request for `testthat`, since it would be nice to avoid regex altogether for this use case. – pete Jun 30 '14 at 00:30
1

Your rexeg matches "Hello" in both cases, thus it doesn't return an error. You''ll need to set up word boundaries \\b from both sides. It would suffice if you wouldn't use punctuations/spaces in here. In order to ditch them too, you'll need to add [^\\s ^\\w]

library(testthat)
expect_message(good(), "\\b^Hello[^\\s ^\\w]\\b")
expect_message(bad(), "\\b^Hello[^\\s ^\\w]\\b")    
## Error: bad() does not match '\b^Hello[^\s ^\w]\b'. Actual value: "Hello!!!!!\n"
David Arenburg
  • 91,361
  • 17
  • 137
  • 196
  • Thanks, but not quite what I needed. e.g.: `expect_message(message("Hello Dave."), "\\b^Hello\\W\\b")` – pete Jun 29 '14 at 10:30
  • That because you've added a space in there. Will need to modify it to escape spaces – David Arenburg Jun 29 '14 at 10:36
  • `expect_message(message("Hello%Dave"), "\\b^Hello[^\\s ^\\w]\\b")` I've added a clarification above. I'm trying to test that I have exactly the message I've specified. So while the particular counter-examples I've given need to fail, that's not sufficient: I want everything that's not exactly what I specify to fail too. – pete Jun 29 '14 at 10:46
  • Upvoting because this is helpful though. – pete Jun 29 '14 at 10:51
  • You'll have to escape special characters explicitly I'm afraid. Something like `expect_message(bad(), "\\b^Hello[^\\s ^\\w \\% \\$]\\b")` – David Arenburg Jun 29 '14 at 10:57
  • 1
    Maybe I'm missing something... would this work `expect_message(bad(), "^Hello\\n$")` – GSee Jun 29 '14 at 13:21
  • @GSee, You should post it as an answer probably, the regex is stronger with you – David Arenburg Jun 29 '14 at 13:23