Hamcrest is the well-known framework used for unit testing in the Java ecosystem. It’s bundled in JUnit and simply put, it uses existing predicates – called matcher classes – for making assertions.
In this tutorial, we will explore the Hamcrest API and learn how to take advantage of it to write neater and more intuitive unit tests for our software.
2. Hamcrest Setup
We can use Hamcrest with maven by adding the following dependency to our pom.xml file:
The latest version of this library can always be found here.
3. An Example Test
Hamcrest is commonly used with junit and other testing frameworks for making assertions. Specifically, instead of using junit‘s numerous assert methods, we only use the API’s single assertThat statement with appropriate matchers.
Let’s look at an example that tests two Strings for equality regardless of case. This should give us a clear idea about how Hamcrest fits in to a testing method:
public class StringMatcherTest {
@Test
public void given2Strings_whenEqual_thenCorrect() {
String a = "foo";
String b = "FOO";
assertThat(a, equalToIgnoringCase(b));
}
}
In the following sections we shall take a look at several other common matchers Hamcrest offers.
4. The Object Matcher
Hamcrest provides matchers for making assertions on arbitrary Java objects.
To assert that the toString method of an Object returns a specified String:
@Test
public void givenBean_whenToStringReturnsRequiredString_thenCorrect(){
Person person=new Person("Barrack", "Washington");
String str=person.toString();
assertThat(person,hasToString(str));
}
We can also check that one class is a sub-class of another:
@Test
public void given2Classes_whenOneInheritsFromOther_thenCorrect(){
assertThat(Cat.class,typeCompatibleWith(Animal.class));
}
}
5. The Bean Matcher
We can use Hamcrest‘s Bean matcher to inspect properties of a Java bean.
Assume the following Person bean:
public class Person {
String name;
String address;
public Person(String personName, String personAddress) {
name = personName;
address = personAddress;
}
}
We can check if the bean has the property, name like so:
@Test
public void givenBean_whenHasValue_thenCorrect() {
Person person = new Person("Baeldung", 25);
assertThat(person, hasProperty("name"));
}
We can also check if Person has the address property, initialized to New York:
@Test
public void givenBean_whenHasCorrectValue_thenCorrect() {
Person person = new Person("Baeldung", "New York");
assertThat(person, hasProperty("address", equalTo("New York")));
}
We can as well check if two Person objects are constructed with the same values:
@Test
public void given2Beans_whenHavingSameValues_thenCorrect() {
Person person1 = new Person("Baeldung", "New York");
Person person2 = new Person("Baeldung", "New York");
assertThat(person1, samePropertyValuesAs(person2));
}
6. The Collection Matcher
Hamcrest provides matchers for inspecting Collections.
Simple check to find out if a Collection is empty:
@Test
public void givenCollection_whenEmpty_thenCorrect() {
List<String> emptyList = new ArrayList<>();
assertThat(emptyList, empty());
}
When our Collection is a Map, we can use the following matchers in these respective functions:
To check if it contains a given key:
@Test
public void givenMapAndKey_whenKeyFoundInMap_thenCorrect() {
Map<String, String> map = new HashMap<>();
map.put("blogname", "baeldung");
assertThat(map, hasKey("blogname"));
}
and a given value:
@Test
public void givenMapAndValue_whenValueFoundInMap_thenCorrect() {
Map<String, String> map = new HashMap<>();
map.put("blogname", "baeldung");
assertThat(map, hasValue("baeldung"));
}
and finally a given entry (key, value):
@Test
public void givenMapAndEntry_whenEntryFoundInMap_thenCorrect() {
Map<String, String> map = new HashMap<>();
map.put("blogname", "baeldung");
assertThat(map, hasEntry("blogname", "baeldung"));
}
7. The Number Matcher
The Number matchers are used to perform assertions on variables of the Number class.
To check greaterThan condition:
@Test
public void givenAnInteger_whenGreaterThan0_thenCorrect() {
assertThat(1, greaterThan(0));
}
To check greaterThan or equalTo condition:
@Test
public void givenAnInteger_whenGreaterThanOrEqTo5_thenCorrect() {
assertThat(5, greaterThanOrEqualTo(5));
}
To check lessThan condition:
@Test
public void givenAnInteger_whenLessThan0_thenCorrect() {
assertThat(-1, lessThan(0));
}
To check lessThan or equalTo condition:
@Test
public void givenAnInteger_whenLessThanOrEqTo5_thenCorrect() {
assertThat(-1, lessThanOrEqualTo(5));
}
To check closeTo condition:
@Test
public void givenADouble_whenCloseTo_thenCorrect() {
assertThat(1.2, closeTo(1, 0.5));
}
Let’s pay close attention to the last matcher, closeTo. The first argument, the operand, is the one to which the target is compared and the second argument is the allowable deviation from the operand . This means that if the target is operand+deviation or operand-deviation, then the test will pass.
8. The Text Matcher
Assertion on Strings is made easier, neater and more intuitive with Hamcrest‘s text matchers. We are going to take a look at them in this section.
Finally, we can check for equality of two Strings regardless of case:
@Test
public void given2Strings_whenEqual_thenCorrect() {
String a = "foo";
String b = "FOO";
assertThat(a, equalToIgnoringCase(b));
}
9. The Core API
The Hamcrest core API is to be used by third-party framework providers. However, it offers us some great constructs to make our unit tests more readable and also some core matchers that can be used just as easily.
Readability with the is construct on a matcher:
@Test
public void given2Strings_whenIsEqualRegardlessWhiteSpace_thenCorrect() {
String str1 = "text";
String str2 = " text ";
assertThat(str1, is(equalToIgnoringWhiteSpace(str2)));
}
We can define our own matcher by extending TypeSafeMatcher. In this section, we will create a custom matcher which allows a test to pass only when the target is a positive integer.
public class IsPositiveInteger extends TypeSafeMatcher<Integer> {
public void describeTo(Description description) {
description.appendText("a positive integer");
}
@Factory
public static Matcher<Integer> isAPositiveInteger() {
return new IsPositiveInteger();
}
@Override
protected boolean matchesSafely(Integer integer) {
return integer > 0;
}
}
We need only to implement the matchSafely method which checks that the target is indeed a positive integer and the describeTo method which produces a failure message in case the test does not pass.
Here is a test that uses our new custom matcher:
@Test
public void givenInteger_whenAPositiveValue_thenCorrect() {
int num = 1;
assertThat(num, isAPositiveInteger());
}
and here is a failure message we get since we have passed in a non-positive integer:
java.lang.AssertionError: Expected: a positive integer but: was <-1>
11. Conclusion
In this tutorial, we have explored the Hamcrest API and learnt how we can write better and more maintainable unit tests with it.
The full implementation of all these examples and code snippets can be found in my Hamcrest github project – this is an Eclipse based project, so it should be easy to import and run as it is.
1. Overview
Hamcrest is the well-known framework used for unit testing in the Java ecosystem. It’s bundled in JUnit and simply put, it uses existing predicates – called matcher classes – for making assertions.
In this tutorial, we will explore the Hamcrest API and learn how to take advantage of it to write neater and more intuitive unit tests for our software.
2. Hamcrest Setup
We can use Hamcrest with maven by adding the following dependency to our pom.xml file:
The latest version of this library can always be found here.
3. An Example Test
Hamcrest is commonly used with junit and other testing frameworks for making assertions. Specifically, instead of using junit‘s numerous assert methods, we only use the API’s single assertThat statement with appropriate matchers.
Let’s look at an example that tests two Strings for equality regardless of case. This should give us a clear idea about how Hamcrest fits in to a testing method:
In the following sections we shall take a look at several other common matchers Hamcrest offers.
4. The Object Matcher
Hamcrest provides matchers for making assertions on arbitrary Java objects.
To assert that the toString method of an Object returns a specified String:
We can also check that one class is a sub-class of another:
5. The Bean Matcher
We can use Hamcrest‘s Bean matcher to inspect properties of a Java bean.
Assume the following Person bean:
We can check if the bean has the property, name like so:
We can also check if Person has the address property, initialized to New York:
We can as well check if two Person objects are constructed with the same values:
6. The Collection Matcher
Hamcrest provides matchers for inspecting Collections.
Simple check to find out if a Collection is empty:
To check the size of a Collection:
We can also use it to assert that an array has a required size:
To check if a Collection contains given members, regardless of order:
To further assert that the Collection members are in given order:
To check if an array has a single given element:
We can also use an alternative matcher for the same test:
Or still we can do the same with a different matcher like so:
We can also check if the array contains given elements regardless of order:
To check if the array contains given elements but in the given order:
When our Collection is a Map, we can use the following matchers in these respective functions:
To check if it contains a given key:
and a given value:
and finally a given entry (key, value):
7. The Number Matcher
The Number matchers are used to perform assertions on variables of the Number class.
To check greaterThan condition:
To check greaterThan or equalTo condition:
To check lessThan condition:
To check lessThan or equalTo condition:
To check closeTo condition:
Let’s pay close attention to the last matcher, closeTo. The first argument, the operand, is the one to which the target is compared and the second argument is the allowable deviation from the operand . This means that if the target is operand+deviation or operand-deviation, then the test will pass.
8. The Text Matcher
Assertion on Strings is made easier, neater and more intuitive with Hamcrest‘s text matchers. We are going to take a look at them in this section.
To check if a String is empty:
To check if a String is empty or null:
To check for equality of two Strings while ignoring white space:
We can also check for the presence of one or more sub-strings in a given String in a given order:
Finally, we can check for equality of two Strings regardless of case:
9. The Core API
The Hamcrest core API is to be used by third-party framework providers. However, it offers us some great constructs to make our unit tests more readable and also some core matchers that can be used just as easily.
Readability with the is construct on a matcher:
The is construct on a simple data type:
Negation with the not construct on a matcher:
The not construct on a simple data type:
Check if a String contains a given sub-string:
Check if a String starts with given sub-string:
Check if a String ends with given sub-string:
Check if two Objects are of the same instance:
Check if an Object is an instance of a given class:
Check if all members of a Collection meet a condition:
Check that a String is not null:
Chain conditions together, test passes when target meets any of the conditions, similar to logical OR:
Chain conditions together, test passes only when target meets all conditions, similar to logical AND:
10. A Custom Matcher
We can define our own matcher by extending TypeSafeMatcher. In this section, we will create a custom matcher which allows a test to pass only when the target is a positive integer.
We need only to implement the matchSafely method which checks that the target is indeed a positive integer and the describeTo method which produces a failure message in case the test does not pass.
Here is a test that uses our new custom matcher:
and here is a failure message we get since we have passed in a non-positive integer:
11. Conclusion
In this tutorial, we have explored the Hamcrest API and learnt how we can write better and more maintainable unit tests with it.
The full implementation of all these examples and code snippets can be found in my Hamcrest github project – this is an Eclipse based project, so it should be easy to import and run as it is.