Home / Java / Easier JUnit testing with hamcrest

Easier JUnit testing with hamcrest

Have you ever thought that JUnit assertions are not really readable and do not correspond to natural language? It is a mess that the expected value is the first argument on an assert? This would not be like the spoken language where you would say “assert that this value is equal to this expected one” ? Or have you had tests where the expected value and the value to test were inverted? In this case you have not found an old friend of JUnit called hamcrest.

Strings

Let’s give you a small sample. We want check a string if it contains “foo”. Till this moment you would write something like the following:

String resultString = getSomeString();
assertEquals(resultString, "foo");

Oops you see the mistake? Yes you’re right; the attributes for assertEquals must be flipped. I think the better way to check the value would be this (I use static imports from “org.hamcrest.Matchers” otherwise it would not be as readable):

final String resultString = getSomeString();
assertThat(resultString, is(equalTo("foo")));

Starts with

It will be much more interesting if we want to check if a string starts or ends with a special substring. Till now you would write something like this:

assertTrue(resultString.startsWith(prefix));

But there are some problems.
- resultString may be null
- if resultString does not start with prefix the message would not help us
Here the better solution

assertThat(resultString, startsWith(prefix));

If we have a look to the AssertionError we will see something like this:
java.lang.AssertionError:
Expected: a string starting with “f”
got: “bar”
I think this tells enough. There are similar methods to check whether a string contains or ends with a certain substring.

Collections

There are also very useful matchers for checking Collections. Here a sample to check the size and another to check if the collection contains an element.

assertThat(collection, hasSize(1));
assertThat(strings, contains("bar"));

If you don’t want new dependencies in your project, you can use the matchers within default JUnit package. They are located at “org.junit.matchers.JUnitMatchers”. But I promise, you will not be happy with this small set of matchers.

Problems

If you are using hamcrest in combination with JUnit the following exception might occur in case of mismatch:
java.lang.NoSuchMethodError: org.hamcrest.Matcher.describeMismatch(Ljava/lang/Object;Lorg/hamcrest/Description;)V

This occurs when the hamcrest version provided by JUnit does not match the hamcrest version you previously downloaded. There are two solutions:

  • put hamcrest.jar before the junit.jar in your classpath
  • download the hamcrest free version of JUnit
  • If you experience troubles nonetheless you might want to look into other libraries which also contain parts of hamcrest.