As of JUnit 4.4, if you happen to peek into the distributed JAR you'll notice something a little off: in addition to the org.junit.* packages there is this a funny-looking org.hamcrest.* package sticking out like a sore thumb. You may have seen other projects pick up a dependency on Hamcrest lately as well, and I bet you're wondering what it is. Let's get to the bottom of it.

Introduction

The "I'm Feeling Lucky" Google search for the term hamcrest currently takes you to the project's Google Code page that states Hamcrest:

Provides a library of matcher objects (also known as constraints or predicates) allowing ‘match' rules to be defined declaratively, to be used in other frameworks.

That's a pretty good description if you already know what a Matcher is… but it doesn't explain much for a beginner. So what does Hamcrest really do for you?

A good way to think of it is that Hamcrest is to objects what regular expressions are to text. Hamcrest provides you with a set of methods that effectively define a DSL to do pattern-matching on objects.

What can you use it for? Well, like regular expressions, the possibilities are endless. Some really novel uses have come about recently, but the most prominent use has been in the area of testing - hence the JUnit dependency.

A Brief History

Hamcrest evolved out of the library JMock, being used to write specialized constraints on what you expected to happen to a Mock object when standing in for a real implementation. A more fluent assertion syntax arose from these constraints which allowed you to chain together main constraint calls under a single assertThat method. Later JMock's author, Joe Walnes, refactored the constraint API out into its own library that he called Hamcrest as people became interested in using it outside of a testing framework for all kinds of different things. He also started calling the constraints "matchers" though they can go by both names or, in some circles, "predicates." Other testing frameworks and even JUnit, notorious for not requiring any dependencies and staying conceptually small, have picked it up.

All those old friendly org.junit.Assert.* static methods are still around in JUnit 4.4+. They're useful for certain things, but by and large they've fallen out of style. The new kid on the block, JUnit's assertThat method allows you to pass a Matcher in to create an assertion for which you would otherwise use a specialized-assert method. Why is assertThat so useful? A few different reasons. Not only does it provide a more generic way to specify assertions, it also alows the framework to know specifically what you're trying to assert. That allows the framework to generate failure messages for you.

Fail message… win?

It's always been a good idea to use the overridden version of assertX method that also takes a String for a failure message, for example:

assertTrue(blackbeard.getOccupations().contains("pirate") ||
 blackbeard.getOccupations().contains("captain"),
 "Expected Blackbeard to be a pirate or a captain");

If we passed in an object representing a childhood version of Blackbeard, say, (before he took to the high-seas) then we'd expect to see our failure message:

java.lang.AssertionError: Expected Blackbeard to be a pirate or a captain

It's always been a good idea to provide these messages. But there's no getting around the fact that they're repetitive, tedious, and redundant.

Using Hamcrest matchers alongside assertThat makes JUnit smart enough to generate meaningful failure messages for you: writing your assertion with Hamcrest matchers provides the framework with enough contextual information to generate meaningful failure messages on your behalf. No need to maintain an extra arbitrary String to make sense of your failed assertions:

assertThat(blackbeard.getOccupations(), anyOf(hasItem("pirate"),hasItem("captain")));

This may not look like much of an improvement, but it also doesn't read any worse. We can ditch the extra String parameter as well. When this fails we'll get a pretty cool failure message for free:

java.lang.AssertionError:
 Expected: (a collection containing "pirate" or a collection containing "captain")
 got:  [] >

Note: I'm using JUnit 4.6 - in order to get this syntax to work you need to do some static imports:

import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.matchers.JUnitMatchers.*;

Though I haven't been able to get this to work, it looks like there's still work being done to make this DSL read more fluently in JUnit; something like:

assertThat(blackbeard.getOccupations(), either(hasItem("pirate")).or(hasItem("captain")));

Other Cool Stuff

Getting Reused

TestNG, JMock and many other testing frameworks will certainly benefit from what Hamcrest offers, but we're starting to see this being used in many other places as well. I'll be interested to see how well matchers work together or are maintained seeing that they're relatively easy to create. Hopefully frameworks will contribute useful matchers back to the project.

Chaining

Because the matchers are implemented as a DSL using the method chaining idiom, they're extremely easy to combine and extend.

Matchers For Regular Expressions

To bring the blog post full circle, I found this earlier tonight: the Hamcrest Text Patterns project. Its goal is to have you write Hamcrest-style regular expressions using matchers that produce much more readable regular expression code. For example, have a look at this test that I found in the project:

PatternMatcher emailAddressMatcher = new PatternMatcher(sequence(
 capture("user", oneOrMore(anyCharacter())),
 "@",
 capture("host", oneOrMore(anyCharacter()))
));
 
PatternMatcher mailToURLMatcher = new PatternMatcher(sequence(
 capture("scheme", text("mailto")),
 ":",
 capture("email", emailAddressMatcher)
));
 
assertThat("mailto:npryce@users.sf.net", matchesPattern(mailToURLMatcher));

By providing a friendly name for each capture (user, host, scheme, email) you can provide meaningful messages programmatically about what doesn't match up when something doesn't match.

Many more uses

Check out UsesOfHamcrest to see more ways to apply Matchers: Processing collections, creating filters to use in logging, etc.

Conclusion

I hope you choose to take a closer look at Hamcrest because it brings a big bang-for-the-buck and has the potential to guide us to more human-friendly, readable code.

Further Reading