I just love the assertion syntax of ScalaTest. It's easy to read and easy to write and looks like this:

23 should be >= (12)

Even if you know nothing about ScalaTest it should be easy to understand whats this assertion is about. But what when your assertions get more complex? Like this:

new Frog().color.getGreen() should be >= (80)

Although this assertion certainly isn't rocket science, it is not so easy to see what is getting tested here. How about this?

new Frog() should  be_Greenish

Now that is nice and clean and perfectly possible with ScalaTest. Of course we have to implement be_Greenish since ScalaTest doesn't care so much about Frogs being green. Luckily the implementation is simple:

object be_Greenish extends Matcher[Frog]{
def apply (left : Frog) : MatchResult =
MatchResult(left.color.getGreen >= 80, "The frog is not green enough", "The frog contains to much green" )
}

should expects a Matcher of what ever comes before should. So be_greenish must be a Matcher[Frog]. The Matcher has one method which we need to implement: apply and it takes a Frog as an argument and returns a MatchResult which we can construct using boolean signifying if the frog passed the test represented by the matcher or not, and the messages to use when the test failed and when the test succeed but actually was supposed fail. This makes it possible to negate assertions using not. There is also a variation of MessageResult which takes two more messages as arguments. Those are used when assertions get combined using and or or. In these cases the failure message of a Matcher are only part of a longer sentence and therefore probably shouldn't start with a capital letter.

This approach would works really nice if we were testing some behavior of our frog. Like its ability to jump. We could create matcher that allow us to write things like:

new Frog() should  jump (far)

jump would be a method taking a Distance as an argument and returning a Matcher[Frog]. far would be an instance of Distance.

But we really just want to test a property. This causes the weird name 'be_Greenish' with the odd underscore. There is a easier and therefore better way to write these matchers: BePropertyMatcher:

object greenish extends BePropertyMatcher[Frog]{
def apply(left : Frog) = BePropertyMatchResult(left.color.getGreen >= 80, "greenish")
}

This allows us to write test like:

new Frog(Color.blue)  should not  be(greenish)

So whenever you write tests where the assertions are not trivial and possibly repeated in multiple tests consider to implement your own matchers. It's easy and makes for way easier to read tests.

Talks

Wan't to meet me in person to tell me how stupid I am? You can find me at the following events: