How to use JUnit4 Hamcrest Matchers
JUnit borrows matchers from a library called Hamcrest, which look a lot like RSpec matchers in Ruby. They can be tricky to write, but end up being much more readable for complex assertions. At its simplest case, we can turn this assertion
assertTrue(board.isGameOver());
into
assertThat(board.isGameOver(), is(true));
It's slightly wordier, but I think it reads in English a little better, and is capable of still-readable more-complex assertions. The is()
function here isn't from extending TestCase (JUnit 4 no longer needs this, that was a JUnit 3 thing). It's actually a static import, although there seems to be conflicting information on the internet on what needs to be imported. I found these to work in most cases:
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
From what I can tell, JUnit pulled in some, but not all of the matchers from Hamcrest. There are still some useful matchers in Hamcrest, so I like to import them, and there aren't any namespace collisions. It doesn't add any additional lines to your POM since you can actually leave out the JUnit dependency and just import the Hamcrest library (since it itself depends on JUnit).
<dependency>
<groupid>org.hamcrest</groupid>
<artifactid>hamcrest-all</artifactid>
<version>1.3</version>
<scope>test</scope>
</dependency>
In the actual test that motivated this post, I had a really specific need to test that a method would return a list which contained at any index a POJO bean which had properties for settlement
being an instance of a Village class and score
being 42. I was able to express this as
assertThat(
settlementScoresList,
hasItem(allOf(
hasProperty("settlement", instanceOf(Village.class)),
hasProperty("score", is(42)))));