Matchers
Jakob Jenkov |
Matchers is an external addition to the JUnit framework. Matchers were added by the framework called Hamcrest. JUnit 4.8.2 ships with Hamcrest internally, so you don't have to download it, and add it yourself.
Matchers are used with the org.junit.Assert.assertThat()
method, which looks like this:
public void assertThat(Object o, Matcher matcher){ ... }
You can implement your own Matcher's, but JUnit (Hamcrest) comes with a few builtin matchers you can use. Here are a few examples:
import static org.junit.Assert.*; import static org.hamcrest.CoreMatchers.*; import org.junit.Test; public class MyMatcherTest { @Test public void testWithMatchers() { assertThat("this string", is("this string")); assertThat(123, is(123)); } }
The assertThat()
method takes an object and a Matcher
implementation.
It is the Matcher
that determines if the test passes or fails. The assertThat()
method just takes care of the "plumming" - meaning calling the Matcher
with the
given object.
JUnit (Hamcrest, really) comes with a collection of builtin matchers you can use. In the example above,
the org.hamcrest.CoreMatchers.is()
method is used to create a Matcher
. The
Matcher
returned by is()
returns true, if the two values compared are equal,
and false if not.
The assertThat
method throws an exception if the Matcher
returns false. If the
Matcher
returns true, the assertThat()
method returns normally. How the Matcher
returns true or false, I will get back to later in this text. Right now just imagine that it can.
Chaining Matchers
You can chain some matchers, for instance like this:
@Test public void testWithMatchers() { assertThat(123, not( is(345) ) ); }
Notice the chained call not( is(345) )
. This is really two matchers combined.
The is()
method returns one matcher, and the not()
method returns another.
The matcher returned by not()
negates the matcher output of the matcher given as input.
In this case, it is the output of the matcher returned by the is()
method, that
is negated.
Core Matchers
Before you start implementing your own Matcher
's, you should look at the core matchers that come
with JUnit already. Here is a list of the matcher methods:
Core | ||
any() | Matches anything | |
is() | A matcher that checks if the given objects are equal. | |
describedAs() | Adds a descrption to a Matcher | |
Logical | ||
allOf() | Takes an array of matchers, and all matchers must match the target object. | |
anyOf() | Takes an array of matchers, and at least one of the matchers must report that it matches the target object. | |
not() | Negates the output of the previous matcher. | |
Object | ||
equalTo() | A matcher that checks if the given objects are equal. | |
instanceOf() | Checks if the given object is of type X or is compatible with type X | |
notNullValue() + nullValue() |
Tests whether the given object is null or not null. | |
sameInstance() | Tests if the given object is the exact same instance as another. |
Actually, all of the above are static methods which take different parameters, and
return a Matcher
.
You will have to play around with matchers a little, before you get the hang of them. They can be quite handy.
Custom Matchers
You can write your own matchers and plug into the assertThat()
method. Here is an example:
public static Matcher matches(final Object expected){ return new BaseMatcher() { protected Object theExpected = expected; public boolean matches(Object o) { return theExpected.equals(o); } public void describeTo(Description description) { description.appendText(theExpected.toString()); } }; }
The static method matches()
creates a new matcher and returns it.
This matcher is an anonymous subclass of the class BaseMatcher
. The JUnit documentation states that
you should always extend BasreMatcher
rather than implement the Matcher
interface yourself.
Thus, if new methods are added to Matcher
in the future, BaseMatcher
can implement them.
Your subclasses will then automatically get those methods too. That will avoid breaking your code.
Here is how to use this custom matcher:
@Test public void testThat() { MyUnit myUnit = new MyUnit(); assertThat(myUnit.getTheSameObject(), matches("constant string")); }
Simple, isn't it? You just embed the call to the static method matches()
inside the
assertThat()
method.
Tweet | |
Jakob Jenkov |