Search code examples
specs2

How can I use custom messages with mutable specs2 specifications?


I can not seem to get specs2 to print any custom messages.

import org.junit.runner.RunWith
import org.specs2.mutable.Specification
import org.specs2.runner.JUnitRunner

@RunWith(classOf[JUnitRunner])
class MessageSpecs extends Specification {
  "This" should {
    "fail" in {
      true.must(beFalse).setMessage("this should PRINT")
      //true.must(beFalse.setMessage("this should PRINT")) // or maybe this?  no.
      //true.must(beFalse).updateMessage(_ => "this should PRINT") // not this either
    }
  }
}

I simply get the default failure message "the value is true". This is on specs2 3.8.5 using the JUnitRunner via maven. I have not tried this on an sbt project yet. The documentation I can find suggests that this should work.

--- Edit ---

sort-of work-around: true.aka("this should PRINT").must(beFalse) // works

That prints up a bit ugly when used in practice to describe a complicated failure, but at least it prints, so I can add the additional context necessary to more easily understand the failure.


Solution

  • The main issue here comes from the fact that you are using a mutable specification. In a mutable specification exceptions are thrown when a result is incorrect. In that case, before you can even try to set a different message, the test fails (with the original message).

    You have 2 options:

    • set the message on the matcher itself

      false must beTrue.setMessage("ko")
      
    • capture the result with org.specs2.execute.AsResult (this catches exceptions)

      AsResult(false must beTrue).updateMessage("ko")
      

    You will also notice that the API to set/update messages is slightly different depending on setting a message on a MatchResult (for which there is a matched entity) and a Result (which is a more general notion). The former uses setMessage, the latter uses updateMessage.

    And, for the record, there are other ways to add more information to a given failure:

    • use aka to describe the actual value as you noticed

    • use a sentence to describe the full expectation

      "Values are correct" ==> {
        values must beCorrect
      } 
      
    • create a new matcher

      def myMatcher: Matcher[Int] = (i: Int) =>
        (test(i), s"what's wrong with $i")