Write More Understandable Java Tests with Matcher Objects and FEST-Assert
The Matchers Provided in the JUnit Library
JUnit comes bundled with a subset of Hamcrest matchers so you don't have to add any new dependency in your application. These matchers can be found in the org.hamcrest.core
package of the JUnit JAR. Let’s take a look at some of these matchers:
- IsEqual: This matcher tests whether a value is equal to another value. This method uses the
equals
method for testing equality, for example:assertThat("shekhar", equalTo("shekhar"));
It can also be used to match arrays (including multidimensional), for example:
String[] s1 = {"a", "b"};
String[] s2 = {"a", "b"};
assertThat(s2, equalTo(s1));It can also be used with multidimensional arrays as follows:
int[][] i1 = new int[][]{{1, 2}, {3, 4}};
int[][] i2 = new int[][]{{1, 2}, {3, 4}};
assertThat(i2, equalTo(i1)); - Is: Is is a matcher that decorates another matcher, retaining the behavior but allowing the test to be more expressive. For example:
assertThat(name, is(equalTo("shekhar")))
- IsNot: This matcher can be used when you need to test for a non-equality, for example:
It can be read as A is not equal to B.assertThat("A",not("B"))
- IsNull: This matcher can be used when you need to test for nullability. For example:
assertThat(null,nullValue());
assertThat("A",notNullValue()); - AllOf: This matcher takes multiple matchers and evaluates to
true
if all of the passed matchers evaluate totrue
. AllOf uses shortcut evaluation, so subsequent matchers are not called if an earlier matcher evaluate to false. For example:assertThat(list, allOf(notNullValue(),hasSize(1)));
- IsInstanceOf : This matcher tests whether a value is an instance of class. For example:
assertThat(1, instanceOf(Number.class));
assertThat(null, not(instanceOf(String.class)));
JUnit extended these basic matchers and created some custom matchers, which can be found in the org.junit.matchers
package. All the matchers are hosted in a JUnitMatchers class. Let’s look at some of these matchers with a unit test.
import static org.junit.matchers.JUnitMatchers.*;
import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import org.junit.Before;
import org.junit.Test;
public class JUnitMatchersTest {
private List words;
@Before
public void setUp() {
words = Arrays.asList("available", "avenge", "avenue", "average");
}
/**
* This method tests hasItem matcher which takes an element. This matcher
* matches any collection matching an element.
*/
@Test
public void shouldMatchACollectionContainingAElement() {
assertThat(words, hasItem("available"));
}
/**
* This method tests hasItems matcher which takes multiple elements. This
* matcher matches any collection containing every element in the elements.
*/
@Test
public void shouldMatchCollectionContainingMultipleItems() {
assertThat(words, hasItems("available", "avenge", "avenue"));
}
/**
* This method tests hasItem matcher which takes a matcher. This matcher
* matches any collection containing an element matching elementMatcher
*/
@Test
public void shouldMatchCollectionContainingElementMatcher() {
assertThat(words, hasItem(IsEqual.equalTo("available")));
}
/**
* This method tests hasItems matcher which takes multiple matchers.
*/
@SuppressWarnings("unchecked")
@Test
public void shouldMatchCollectionContainingElementMatchers() {
assertThat(
words,
hasItems(containsString("avail"), containsString("ave"),
containsString("average")));
}
/**
* This method tests everyItem matcher. This matcher matches any collection
* in which every element matches elementMatcher.
*/
@Test
public void shouldHaveEveryItemMatchingElementMatcher() {
assertThat(words, everyItem(containsString("av")));
}
}
Getting the Full Power of Hamcrest
So far we have used only a subset of Hamcrest, which comes bundled with JUnit. To get the full power of Hamcrest we have to use the Hamcrest library. You can download the hamcrest-all-1.3.0RC1.jar
from code.google.com. This JAR is not present in any Maven repository so you have to manually install it in your Maven repository.
mvn install:install-file -Dfile=hamcrest-all-1.3.0RC1.jar -DgroupId=org.hamcrest -DartifactId=hamcrest-all -Dversion=1.3.0RC1 -Dpackaging=jar
Here are some of the most important matchers that do are not available in the JUnit library.
- Beans
hasProperty
-- Tests JavaBeans properties
- Collections
array
-- Tests an array's elements against an array of matchershasEntry
,hasKey
,hasValue
-- Test a map that contains an entry, key or valuehasItemInArray
-- Test an array that contains an element
- Number
closeTo
-- Tests whether floating point values are close to a given valuegreaterThan
,greaterThanOrEqualTo
,lessThan
,lessThanOrEqualTo
-- Test ordering
- Text
equalToIgnoringCase
-- Tests string equality, ignoring caseequalToIgnoringWhiteSpace
-- Tests string equality, ignoring differences in runs of whitespacecontainsString
,endsWith
,startsWith
-- Test string matching
Let’s look at some of these matchers more closely:
HasPropertyWithValue :
-- This matcher asserts that a JavaBean property on an argument passed to the mock object meets the provided matcher.
@Test
public void testHamcrestLibrary() {
TeamMate actual = new TeamMate("shekhar", "gulati");
assertThat(actual, hasProperty("firstName",
IsEqual.equalTo("shekhar")));
List team = Arrays.asList(new TeamMate("shekhar", "gulati"),new TeamMate("rahul", "sharma"),new TeamMate("sameer", "arora"));
Matcher withFirstName = hasProperty("firstName", IsEqual.equalTo("shekhar"));
assertThat(team, hasItem(withFirstName));
}IsCollectionWithSize:
This matcher checks whether the collection size satisfies a given matcher.assertThat(list, hasSize(1));
IsMapContaining:
This matcher is for map.
@Test
public void testHamcrestMapMethods() {
Map map = new HashMap();
map.put("shekhar", "Shekhar Gulati");
map.put("test", "test123");
assertThat(map, hasEntry(equalTo("shekhar"), equalTo("Shekhar Gulati")));
assertThat(map, hasEntry(equalTo("test"), equalTo("test123")));
assertThat(map, not(hasEntry(equalTo("shekhar"), equalTo("test123"))));
}IsIterableContainingInAnyOrder
andIsIterableContainingInOrder
-- These matchers are used to test whetheriterable
should be in any order or use natural ordering. You will need to check the use ofcomparator
andcompareTo
.
@Test
public void testIsIterableContainingInAnyOrderAndIsIterableContainingInOrder(){
List list = Arrays.asList("a","b","c");
assertThat(list, contains("a","b","c"));
assertThat(list, contains(equalTo("a"),equalTo("b"),equalTo("c")));
assertThat(list, containsInAnyOrder("c","a","b"));
}
@Test
public void testHamcrestLibraryIsIterableContainingInOrder() {
TeamMate shekhar = new TeamMate("shekhar", "gulati");
TeamMate rahul = new TeamMate("rahul", "sharma");
TeamMate sameer = new TeamMate("sameer", "arora");
List team = Arrays.asList(shekhar, rahul, sameer);
assertThat(team, IsIterableContainingInOrder.contains(new TeamMate(
"shekhar", "gulati"), new TeamMate("rahul", "sharma"),
new TeamMate("sameer", "arora")));
}
While Hamcrest contains lots of built-in matchers, sometimes you will need to write your own matcher to fit your testing needs. (This Hamcrest tutorial explains how to write your own matchers, and you will find a number of Hamcrest extension libraries here.)
Page 2 of 3
This article was originally published on August 31, 2010