The Librarian: Introduction to Test-Driven Development

This will be a series of articles revolving around unit testing where I will work through examples and exploring various aspects of the craft. This is the first installment.

The code associated with this article can be found on GitHub. Future and past installments can be found in The Librarian Archive.

TDDI will try to implement a few requirements for a Library module with books and memberships, extending whatever code we have in a test-driven style (“TDD”) as we go along. I share a few thoughts about the process, show some refactorings and give a few hints for using the IDE.

The level of this article is for junior developers who want to expand their testing horizon.

There’s plenty of information out there which describes what TDD or Test-Driven Development is, the red-green-refactor cycle etc so I won’t delve into too much introductory detail here. See the references at the end for more background-information.

Instead, just get started!
Continue reading “The Librarian: Introduction to Test-Driven Development”

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.

Quicktip! TestNG’s-like junit-dataprovider Instead of JUnit Parameterized Class

We all know JUnit test-classes can be parameterized, which means that for a given set of test-elements the test class is instantiated a few times, but using constructors for that isn’t always what you want.

I’ve taken the StringSortTest from this blog as an example.

@RunWith(Parameterized.class)
public class StringSortTest {

    @Parameters
    public static Collection<Object[]> data() {
        return Arrays.asList(new Object[][] {
                         { "abc", "abc" },
                         { "cba", "abc" },
         });
    }

    private final String input;
    private final String expected;

    public StringSortTest(final String input, final String expected) {
        this.input = input;
        this.expected = expected;
    }

    @Test
    public void testSort() {
        assertEquals(expected, mySortMethod(input));
    }
}

This is pretty darn obnoxious some times if you have multiple sets of data for various tests, which all go through the constructor which would force you to write multiple test classes. TestNG solves this better by allowing to provide separate data sets to individual test methods using the @DataProvider annotation. Continue reading “Quicktip! TestNG’s-like junit-dataprovider Instead of JUnit Parameterized Class”