03 December 2011
Some time ago, JUnit added assertThat
as a replacement to assertEquals
, assertTrue
, assertNull
, etc. Originally, assertions were written as
assertEquals("stupidplebs.com", site.getMostAwesome());
assertTrue(site.isMostAwesomeSite("stupidplebs.com"));
assertNulhl(site.getAwesomerSiteThanStupidPlebs());
This always struck me as a little odd because, especially true for assertEquals
, the order actual and expected parameters order didn't matter which made reading the purpose of the test a little hard to read. That is,
assertEquals("stupidplebs.com", site.getMostAwesome());
is the equivalent to
assertEquals(site.getMostAwesome(), "stupidplebs.com");
Sure, content assist in your IDE and JUnit API orders them as "actual first, expected second" but developers are creatures of habit and can't be trusted to actually put the parameters in that order. Also, and probably more to the point, the test is awkward to read from a grammatical perspective. Read left to right (like English), it's "I'm asserting the equality of 'stupidplebs.com' to the return value of the site objects' getMostAwesome()
method". For assertTrue
it reads as "I'm asserting the truthfulness of the site objects' isMostAwesomeSite()
method". Hard to read, no? Well, at least to me it is, YMMV. To read like an English sentence, your eyes have to jump back and forth between the parts of the assertion.
Then I found out about assertThat
which, at first, seemed too touchy-feely for my liking. After all, tests are blunt and, besides, I've already written a few thousand assertions that I'd have to fix and assertEquals
/True
/Null
/False
/NotNull
/Same
/NotSame
have worked fine so far, so why change now? I decided to give it a go and after some fighting with Eclipse content assist, I was pleased with what I found.
Much to my delight, with assertThat
, the assertion reads more like an English sentence, speeding up comprehension of tests written by other developers and when revisiting tests I haven't seen in a while. For example, the above three tests can be written as:
assertThat(site.getMostAwesome(), is("stupidplebs.com"));
assertThat(site.isMostAwesomeSite("stupidplebs.com"), is(true));
assertThat(site.getAwesomerSiteThanStupidPlebs(), is(nullValue()));
Now the first test reads as:
"I'm asserting that the return value of the site objects' getMostAwesome()
method is 'stupidplebs.com'"
The second reads as "I'm asserting that the return value of site objects' isMostAwesomeSite()
method is true"
Reads more easily, no? Not only that, by standardizing on a single assert method, after a few times reading tests your eyes can skip over the assertThat
part, resulting in:
"the return value of the site objects' getMostAwesome()
method is 'stupidplebs.com'"
With assertThat
, the is()
method you see is called a matcher. There are a number of matchers available and can be chained together, as in:
assertThat(site.isMostAwesomeSite("stupidplebs.com"), is(not(false))));
and
assertThat(site, is(not(nullValue()));
The last example was done to show an example of chaining, it could also be written as:
assertThat(site, is(notNullValue()));
Where there were only so many assert methods available in previous versions of JUnit before having to write your own and dealing with your IDEs fussiness of custom assert methods, with assertThat
, if a combination of matchers doesn't solve your problem, you can write your own matchers by extending org.hamcrest.BaseMatcher. I'll make a mental note to create some custom matchers and post an article about them.