Mixing JUnit, Hamcrest and Mockito: Explaining java.lang.NoSuchMethodError: org/hamcrest/Matcher.describeMismatch

Let’s say you’ve introduced JUnit and Hamcrest matchers to your project by adding the following to your pom.xml

<dependency>
	<groupId>junit</groupId>
	<artifactId>junit</artifactId>
	<version>4.11</version>
</dependency>
<dependency>
	<groupId>org.hamcrest</groupId>
	<artifactId>hamcrest-all</artifactId>
	<version>1.3</version>
</dependency>

For the first time there’s a possibility when running a successful test it’s all peaches and fine, but when it fails you’ll be confronted with a NoSuchMethodError.

java.lang.NoSuchMethodError: org/hamcrest/Matcher.describeMismatch(Ljava/lang/Object;Lorg/hamcrest/Description;)V
at org.hamcrest.collection.IsIterableContainingInOrder$MatchSeries.describeMismatch(IsIterableContainingInOrder.java:83)
at org.hamcrest.collection.IsIterableContainingInOrder$MatchSeries.isMatched(IsIterableContainingInOrder.java:66)
at org.hamcrest.collection.IsIterableContainingInOrder$MatchSeries.matches(IsIterableContainingInOrder.java:52)
at org.hamcrest.collection.IsIterableContainingInOrder.matchesSafely(IsIterableContainingInOrder.java:25)
at org.hamcrest.collection.IsIterableContainingInOrder.matchesSafely(IsIterableContainingInOrder.java:14)
at org.hamcrest.TypeSafeDiagnosingMatcher.matches(TypeSafeDiagnosingMatcher.java:55)
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:12)
at org.junit.Assert.assertThat(Assert.java:865)

This could be due to the fact that JUnit itself brings along its own version of Hamcrest as a transitive dependency. Now if you would be using JUnit 4.11 it would depending on Hamcrest 1.3 already – see here. Getting above error would be weird – since the describeMismatch method is present in org.hamcrest.Matcher interface.

There seems to be an older version of org.hamcrest.Matcher present on the classpath to which org.junit.Assert.assertThat delegates.

If you run this from Eclipse or IntelliJ, there’s a high chance that the IDE uses its own version of JUnit instead of your Maven dependency. You should first rule that out by running mvn clean install -Dtest<yourtest> outside your IDE .

If that still doesn’t work, check which dependencies are present on the classpath by running mvn dependency:tree -Dscope=test which might give you some results like this:

[INFO] +- org.mockito:mockito-all:jar:1.9.5:test
[INFO] +- com.tngtech.java:junit-dataprovider:jar:1.5.0:test
[INFO] |  \- com.google.code.findbugs:annotations:jar:2.0.1:test
[INFO] \- org.hamcrest:hamcrest-all:jar:1.3:test
[INFO] ------------------------------------------------------------------------

This lists all dependencies in the test scope – which possibly allows you to see whether or not another Matcher class is brought in. If you have a lot of dependencies, what often might help is to look for the specifc class within the IDE.

Finding classes in Eclipse
Ctrl-Shift-T to find classes in Eclipse

If we we’re looking in Eclipse for the Matcher classes we e.g. could see that there’s also one in mockito-all-1.9.5.jar – see example screenshot above. Bugger! Seems mockito-all is incompatible with JUnit 4.11 for backwards-compatibility reasons. The Hamcrest version 1.1 Matcher has been packaged within the dependency, so we can not exclude it.

Luckily for us, Mockito allows to us to use a mockito-core dependency instead of mockito-all. Running a dependency check (with dependency:tree or online) shows us it depends on hamcrest-core.

[INFO] +- org.mockito:mockito-core:jar:1.9.5:test
[INFO] |  \- org.hamcrest:hamcrest-core:jar:1.1:test

We can exclude it in the pom.xml and – no more NoSuchMethodError. Here’s the final combination of dependencies in our case:

<dependency>
	<groupId>org.mockito</groupId>
	<artifactId>mockito-core</artifactId>
	<version>1.9.5</version>
	<exclusions>
		<exclusion>
			<artifactId>hamcrest-core</artifactId>
			<groupId>org.hamcrest</groupId>
		</exclusion>
	</exclusions>
</dependency>
<dependency>
	<groupId>junit</groupId>
	<artifactId>junit</artifactId>
	<version>4.11</version>
	<exclusions>
		<exclusion>
			<artifactId>hamcrest-core</artifactId>
			<groupId>org.hamcrest</groupId>
		</exclusion>
	</exclusions>
</dependency>
<dependency>
	<groupId>org.hamcrest</groupId>
	<artifactId>hamcrest-all</artifactId>
	<version>1.3</version>
</dependency>

Featured image on top of this post courtesy of the The Junit / Green Lantern Oath.