Unit Test with Hamcrest in java Unit Test with Hamcrest in java

assertThat() with Hamcrest Matchers

Page content

In this tutorial, we’ll learn how to write efficient Junit test cases in Java using Hamcrest assertThat() with Matchers.

Hamcrest

Hamcrest is a widely used framework for writing unit test cases in Java. Sometimes it becomes difficult to write Junit test cases to test complex conditions, Hamcrest comes in handy in such cases, which provides pre-defined Matchers to specify conditions for Texts (String), Numbers (Integer, Long, Double, and Float), Collections (List, Array, and Map), Objects and many more.

You write unit tests with Hamcrest using assertThat() statement followed by one or more, or nested Matchers. We will look at all of Matcher’s examples in this article. Let’s do the setup first.

Setup Hamcrest

Import the required Hamcrest dependency for Java using Maven (pom.xml) or Gradle (build.gradle), whichever you are using:-

<!-- add dependency in pom.xml -->
<dependency>
  <groupId>org.hamcrest</groupId>
  <artifactId>hamcrest</artifactId>
  <version>2.2</version>
  <scope>test</scope>
</dependency>
// add dependency in build.gradle
dependencies {
    testImplementation 'org.hamcrest:hamcrest:2.2'
}

Import Hamcrest

Once you add the Hamcrest dependency, you can import static Hamcrest assertThat() method and All Matchers in unit test class like this:-

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;

We are ready to write unit test cases with Hamcrest.

Using Hamcrest Matchers

Matcher to check null value

These are quite often used Hamcrest Object Matchers to check the null and non-null value:-

  1. Assert that a given value is Null:-
    @Test
    public void givenValue_whenNull_thenPass() {
        String text = null;
        Integer number = null;
        Boolean flag = null;
        Object obj = null;
    
        // assertThat(null, is(null)); <- throw NullPointerException
    
        assertThat(null, is(nullValue()));    // pass
        assertThat(text, is(nullValue()));    // pass
        assertThat(number, is(nullValue()));  // pass
        assertThat(flag, is(nullValue()));    // pass
        assertThat(obj, is(nullValue()));     // pass
    }
    
  2. Assert that a given value is Not Null:-
    @Test
    public void givenValue_whenNotNull_thenPass() {
        assertThat("a", is(notNullValue()));          // pass
        assertThat(1, is(notNullValue()));            // pass
        assertThat(false, is(notNullValue()));        // pass
        assertThat(new Object(), is(notNullValue())); // pass
    }
    

Text Matchers for String

Hamcrest Text Matchers are used to write easier and neater assertions on String with various conditions. Let’s look at them:-

  1. Assert that a String is empty:-

    @Test
    public void givenString_whenEmpty_thenPass() {
        String text = "";
        assertThat(text, is(emptyString()));
    }
    
  2. Assert that a String is empty or null:-

    @Test
    public void givenString_whenEmptyOrNull_thenPass() {
        String text = null;
        assertThat(text, is(emptyOrNullString()));
    }
    
  3. Assert that a String is not null:-

    @Test
    public void givenString_whenNotNull_thenPass() {
        String text = "notnull";
        assertThat(text, notNullValue());
    }
    
  4. Assert that two Strings are equal ignoring the case:-

    @Test
    public void givenTwoStrings_whenEqualToIgnoringCase_thenPass() {
        String text1 = "foo";
        String text2 = "FOO";
        assertThat(text1, equalToIgnoringCase(text2));
    }
    
  5. Assert that two Strings are equal ignoring the white space:-

    @Test
    public void givenTwoStrings_whenEqualToIgnoringWhiteSpace_thenPass() {
        String text1 = "   my\tfoo  bar ";
        String text2 = " my  foo bar";
        //assertThat(text1, equalToIgnoringWhiteSpace(text2)); // deprecated
        assertThat(text1, equalToCompressingWhiteSpace(text2)); // use this!
    }
    

    Please Note that equalToIgnoringWhiteSpace matcher is deprecated, use equalToCompressingWhiteSpace instead.

  6. Assert that a String contains the given Substring:-

    @Test
    public void givenString_whenContainsGivenSubstring_thenPass() {
        String text = "lordOfTheRings";
        String subtext = "Ring";
        assertThat(text, containsString(subtext));
    }
    
  7. Assert that a String contains the given Substring ignoring the case:-

    @Test
    public void givenString_whenContainsGivenSubstringIgnoringCase_thenPass() {
        String text = "lordOfTheRings";
        String subtext = "RING";
        assertThat(text, containsStringIgnoringCase(subtext));
    }
    
  8. Assert that a String contains one or more Substrings in a given order:-

    @Test
    public void givenString_whenContainsOneOrMoreSubstringsInGivenOrder_thenPass() {
        String text = "lordOfTheRings";
        assertThat(text, stringContainsInOrder(Arrays.asList("lord", "Ring")));
    }
    
  9. Assert that a String starts with a given Substring:-

    @Test
    public void givenString_whenStartsWithGivenSubstring_thenPass() {
        String text = "lordOfTheRings";
        String subtext = "lord";
        assertThat(text, startsWith(subtext));
    }
    
  10. Assert that a String starts with a given Substring ignoring the case:-

    @Test
    public void givenString_whenStartsWithGivenSubstringIgnoringCase_thenPass() {
        String text = "lordOfTheRings";
        String subtext = "LORD";
        assertThat(text, startsWithIgnoringCase(subtext));
    }
    
  11. Assert that a String ends with a given Substring:-

    @Test
    public void givenString_whenEndsWithGivenSubstring_thenPass() {
        String text = "lordOfTheRings";
        String subtext = "Rings";
        assertThat(text, endsWith(subtext));
    }
    
  12. Assert that a String ends with a given Substring ignoring the case:-

    @Test
    public void givenString_whenEndsWithGivenSubstringIgnoringCase_thenPass() {
        String text = "lordOfTheRings";
        String subtext = "RINGS";
        assertThat(text, endsWithIgnoringCase(subtext));
    }
    

Number Matchers for Integer, Long, Double, Float, BigDecimal

Hamcrest Number Matchers are used to write assertions on Numbers (Integer, Long, Double, Float, and BigDecimal) with various conditions. Let’s look at them:-

  1. Assert that an Integer is greater than a given Integer:-
    @Test
    public void givenInt_whenGreaterThanGivenInt_thenPass() {
        assertThat(2, greaterThan(1));
    }
    
  2. Assert that an Integer is greater than or equal to a given Integer:-
    @Test
    public void givenInt_whenGreaterThanOrEqualToGivenInt_thenPass() {
        assertThat(1, greaterThanOrEqualTo(1));
    }
    
  3. Assert that an Integer is less than a given Integer:-
    @Test
    public void givenInt_whenLessThanGivenInt_thenPass() {
        assertThat(-1, lessThan(1));
    }
    
  4. Assert that an Integer is less than or equal to a given Integer:-
    @Test
    public void givenInt_whenLessThanOrEqualToGivenInt_thenPass() {
        assertThat(1, lessThanOrEqualTo(1));
    }
    
  5. Assert that a Double is within the given range specified by the operand and (+/-) error arguments:-
    @Test
    public void givenDouble_whenWithinRange_thenPass() {
        // 0.8 is within range of 1.0 (+/-) 0.2 = 0.8 to 1.2
        assertThat(0.8, is(closeTo(1.0 /*operand*/, 0.2 /*error*/)));
    }
    
  6. Assert that a BigDecimal is within the given range specified by the operand and (+/-) error arguments:-
    @Test
    public void givenBigDecimal_whenWithinRange_thenPass() {
        // 1.8 is within range of 2.0 (+/-) 0.5 = 1.5 to 2.5
        assertThat(new BigDecimal("1.8"), is(closeTo(new BigDecimal("2.0") /*operand*/, new BigDecimal("0.5") /*error*/)));
    }
    

Object Matchers for Java Object

Hamcrest Object Matchers are used to write assertions on Java Objects to check various conditions. Let’s look at them:-

  1. Assert that two Objects are equal using the Object’s equals() method:-
    @Test
    public void givenTwoObjects_whenEquals_thenPass() {
        User user1 = User.builder().firstName("Adam").build();
        User user2 = User.builder().firstName("Adam").build();
        assertThat(user1, equalTo(user2));
    }
    
  2. Assert that two objects are referring to the same instance:-
    @Test
    public void givenTwoObjects_whenSameInstance_thenPass() {
        User user = User.builder().firstName("Adam").build();
        assertThat(user, sameInstance(user));
    }
    
  3. Assert that an Object is an instance of the given Class:-
    @Test
    public void givenObject_whenInstanceOfGivenClass_thenPass() {
        User user = User.builder().firstName("Adam").lastName("Smith").build();
        assertThat(user, instanceOf(User.class));
    }
    
  4. Assert that toString() method of an Object returns the given String:-
    @Test
    public void givenObject_whenToStringMethodReturnsGivenString_thenPass() {
        User user = User.builder().firstName("Adam").lastName("Smith").build();
        String str = user.toString();
        assertThat(user, hasToString(str));
    }
    
  5. Assert that a Class is a subclass of given another class:-
    @Test
    public void given2Classes_whenFirstClassChildOfSecondClass_thenCorrect(){
        assertThat(Integer.class, typeCompatibleWith(Number.class));
    }
    

Bean Matchers for Java Object’s instance

Hamcrest Bean Matchers are used to test the properties of a Java Object instance.

Let’s create an instance of User class and assert them:-

@Data
@Builder
public class User {
    private String firstName;
    private Integer age;
    private Boolean isPremiumUser;
}
  1. Assert that an Object’s instance has a property with the given name:-
    @Test
    public void givenObject_whenHasGivenProperties_thenPass() {
        User user = User.builder().build();
    
        assertThat(user, hasProperty("firstName"));
        assertThat(user, hasProperty("age"));
        assertThat(user, hasProperty("isPremiumUser"));
    }
    
  2. Assert that an Object’s instance has a property with the given name and value:-
    @Test
    public void givenObject_whenHasPropertyWithGivenNameAndValue_thenPass() {
        User user = User.builder().firstName("Adam").age(22).isPremiumUser(true).build();
    
        assertThat(user, hasProperty("firstName", equalTo("Adam")));
        assertThat(user, hasProperty("age", equalTo(22)));
        assertThat(user, hasProperty("isPremiumUser", equalTo(true)));
    }
    
  3. Assert that two Object’s instances have all properties with the same values:-
    @Test
    public void givenTwoObjects_whenSamePropertyValues_thenPass() {
        User user1 = User.builder().firstName("Adam").age(22).isPremiumUser(true).build();
        User user2 = User.builder().firstName("Adam").age(22).isPremiumUser(true).build();
    
        assertThat(user1, samePropertyValuesAs(user2));
    }
    
  4. Assert that two Object’s instances have properties with the same values excluding one or more ignore properties specified:-
    @Test
    public void givenTwoObjects_whenSamePropertyValuesExcludingIgnoredProps_thenPass() {
        User user1 = User.builder().firstName("Adam").age(22).isPremiumUser(true).build();
        User user2 = User.builder().firstName("Adam").age(18).isPremiumUser(false).build();
    
        assertThat(user1, samePropertyValuesAs(user2, "age", "isPremiumUser"));
    }
    
    The above two instances have the same firstName value and we ignored the age and isPremiumUser properties from comparison.

Collection Matchers for List

Hamcrest Collection Matchers can be used for List assertions. Let’s look at examples:-

  1. Assert that a List is empty:-

    @Test
    public void givenList_whenEmpty_thenPass() {
        List<String> list = new ArrayList<>();
        assertThat(list, empty());
    }
    
  2. Assert that a List is of a given size:-

    @Test
    public void givenList_whenSizeMatches_thenPass() {
        List<String> list = Arrays.asList("lord", "of", "the", "rings");
        assertThat(list, hasSize(4));
        assertThat(list, iterableWithSize(4));
    }
    

    Both matchers hasSize and iterableWithSize have the same results and can be used alternatively.

  3. Assert that a List contains all the given values in the same order:-

    @Test
    public void givenList_whenContainsAllValuesInSameOrder_thenPass() {
        List<String> list = Arrays.asList("lord", "of", "the", "rings");
        assertThat(list, contains("lord", "of", "the", "rings"));
    }
    

    The contains matcher should have the same number of specified items as the length of the list for a positive match.

  4. Assert that a List contains all the given values in any order:-

    @Test
    public void givenList_whenContainsAllValuesInAnyOrder_thenPass() {
        List<String> list = Arrays.asList("lord", "of", "the", "rings");
        assertThat(list, containsInAnyOrder("rings", "of", "the", "lord"));
    }
    

    Same as contains, the containsInAnyOrder matcher should have the same number of specified items as the length of the list for a positive match. Though they can be in any order.

  5. Assert that a List contains one or more given values in the relative order:-

    @Test
    public void givenList_whenContainsValuesInRelativeOrder_thenPass() {
        List<String> list = Arrays.asList("lord", "of", "the", "rings");
        assertThat(list, containsInRelativeOrder("of", "rings"));
    }
    
  6. Assert that a List contains the given value:-

    @Test
    public void givenList_whenContainsGivenValue_thenPass() {
        List<String> list = Arrays.asList("lord", "of", "the", "rings");
        assertThat(list, hasItem("lord"));
        assertThat("of", is(in(list)));
    }
    

    Both the matchers in the example have the same result and can be used alternatively.

  7. Assert that a List contains the given value with the specified condition:-

    @Test
    public void givenList_whenContainsGivenValueWithCondition_thenPass() {
        List<String> list = Arrays.asList("lord", "of", "the", "rings");
        assertThat(list, hasItem(equalTo("of")));
        assertThat(list, hasItem(startsWith("th")));
        assertThat(list, hasItem(endsWith("ngs")));
    }
    

    Matchers can be nested together for more complex conditions e.g. hasItem is nested with equalsTo, startsWith, and endsWith in the above example.

  8. Assert that List contains one or more given values with the specified condition:-

    @Test
    public void givenList_whenContainsOneOrMoreGivenValuesWithCondition_thenPass() {
        List<String> list = Arrays.asList("lord", "of", "the", "rings");
        assertThat(list, hasItems(startsWith("ring"), endsWith("ord"), equalTo("of")));
    }
    
  9. Assert that every item in the List matches the given condition:-

    @Test
    public void givenList_whenEveryItemMatchesCondition_thenPass() {
        List<String> list = Arrays.asList("bar", "baz");
        assertThat(list, everyItem(startsWith("ba")));
    }
    

Collection Matchers for Array

Hamcrest Collection Matchers can also be used for Array assertions. Let’s look at examples:-

  1. Assert that Array is of the given size:-

    @Test
    public void givenArray_whenGivenSize_thenPass() {
        String[] arrayItems = { "lord", "of", "the", "rings" };
        assertThat(arrayItems, arrayWithSize(4));
    }
    
  2. Assert that an Array has the given item:-

    @Test
    public void givenArray_whenHasItemInArray_thenPass() {
        String[] arrayItems = { "lord", "of", "the", "rings" };
        assertThat(arrayItems, hasItemInArray("lord"));
        assertThat("of", oneOf(arrayItems));
        assertThat("the", is(in(arrayItems)));
    }
    

    All matchers in the example have the same result and can be used alternatively.

  3. Assert that an Array contains all the given items in the same order:-

    @Test
    public void givenArray_whenContainsAllItemsInSameOrder_thenPass() {
        String[] arrayItems = { "lord", "of", "the", "rings" };
        assertThat(arrayItems, arrayContaining("lord", "of", "the", "rings"));
    }
    

    The arrayContaining matcher should have the same number of specified items as the length of the array for a positive match.

  4. Assert that an Array contains all the given values in any order:-

    @Test
    public void givenArray_whenContainsAllValuesInAnyOrder_thenPass() {
        String[] arrayItems = { "lord", "of", "the", "rings" };
        assertThat(arrayItems, arrayContainingInAnyOrder("rings", "of", "the", "lord"));
    }
    

    Same as arrayContaining, the arrayContainingInAnyOrder matcher should have the same number of specified items as the length of the array for a positive match. Though they can be in any order.


Collection Matchers for Map

Hamcrest Collection Matchers provide assertions for Map to check key, value and entry. Let’s look at examples:-

  1. Assert that a Map is empty:-
    @Test
    public void givenMap_whenEmpty_thenPass() {
        Map<String, String> myMap = new HashMap<>();
        assertThat(myMap, is(anEmptyMap()));
    }
    
  2. Assert that the Map has given size:-
    @Test
    public void givenMap_whenSizeMatched_thenPass() {
        Map<String, String> myMap = Map.of("key1", "value1", "key2", "value2");
        assertThat(myMap, is(aMapWithSize(equalTo(2))));
    }
    
  3. Assert that the Map has a given Key:-
    @Test
    public void givenMap_whenHasGivenKey_thenPass() {
        Map<String, String> myMap = Map.of("myKey", "myValue");
        assertThat(myMap, hasKey(startsWith("my")));
        assertThat(myMap, hasKey(endsWith("Key")));
    }
    
  4. Assert that the Map has a given Key with the specified condition:-
    @Test
    public void givenMap_whenHasGivenKeyWithCondition_thenPass() {
        Map<String, String> myMap = Map.of("myKey", "myValue");
        assertThat(myMap, hasKey(startsWith("my")));
        assertThat(myMap, hasKey(endsWith("Key")));
    }
    
  5. Assert that the Map has a given Value:-
    @Test
    public void givenMap_whenHasGivenValue_thenPass() {
        Map<String, String> myMap = Map.of("myKey", "myValue");
        assertThat(myMap, hasValue("myValue"));
    }
    
  6. Assert that the Map has a given Value with the specified condition:-
    @Test
    public void givenMap_whenHasGivenValueWithCondition_thenPass() {
        Map<String, String> myMap = Map.of("myKey", "myValue");
        assertThat(myMap, hasValue(startsWith("my")));
        assertThat(myMap, hasValue(endsWith("Value")));
    }
    
  7. Assert that the Map has a given Entry:-
    @Test
    public void givenMap_whenHasGivenEntry_thenPass() {
        Map<String, String> myMap = Map.of("myKey", "myValue");
        assertThat(myMap, hasEntry("myKey", "myValue"));
        assertThat(myMap, hasEntry(endsWith("Key"), endsWith("Value")));
    }
    
  8. Assert that the Map has a given Entry with the specified condition:-
    @Test
    public void givenMap_whenHasGivenEntryWithCondition_thenPass() {
        Map<String, String> myMap = Map.of("myKey", "myValue");
        assertThat(myMap, hasEntry("myKey", "myValue"));
        assertThat(myMap, hasEntry(endsWith("Key"), endsWith("Value")));
    }
    

Logical Matchers - NOT, AND, OR

Hamcrest Logical Matchers can be used for chaining the matcher conditions with logical operators.

Matcher Logical Operator
not NOT
anyOf OR
allOf AND
anyOf(allOf(), not()) OR (AND, NOT)
either...or OR
both...and AND

Let’s look at the examples:-

  1. Assert that two Strings are not equal:-
    @Test
    public void givenTwoStrings_whenNotEquals_thenPass() {
        String text1 = "text1";
        String text2 = "text2";
        assertThat(text1, not(equalTo(text2)));
    }
    
  2. Assert that a String matches with any of the given conditions:-
    @Test
    public void givenString_whenAnyOfGivenConditionsMatch_thenPass() {
        String text = "lord of the rings";
        assertThat(text, anyOf(startsWith("lord"), containsString("power")));
    }
    
  3. Assert that a String matches with all of the given conditions:-
    @Test
    public void givenString_whenAllOfGivenConditionsMatch_thenPass() {
        String text = "lord of the rings";
        assertThat(text, allOf(startsWith("lord"), endsWith("rings")));
    }
    
  4. Assert that a String matches the nested condition using AND and OR operators:-
    @Test
    public void givenString_whenComplexConditionMatch_thenPass() {
        String text = "lord of the rings";
        assertThat(text, anyOf(allOf(startsWith("lord"), endsWith("rings")), endsWith("power")));
    }
    
  5. Assert that a String matches either of the two given conditions:-
    @Test
    public void givenString_whenEitherConditionMatch_thenPass() {
        String text = "lord of the rings";
        assertThat(text, either(startsWith("lord")).or(endsWith("power")));
    }
    
  6. Assert that a String matches both of the given conditions:-
    @Test
    public void givenString_whenBothConditionMatch_thenPass() {
        String text = "lord of the rings";
        assertThat(text, both(startsWith("lord")).and(endsWith("rings")));
    }
    

Writing Custom Matcher

Hamcrest comes with lots of useful matchers, but also provides you the ability to write your custom matcher to fit your testing needs.

Let’s write a custom matcher for testing if a given number is a prime number.

package com.example.assertion;

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;

import java.util.stream.IntStream;

public class IsPrimeNumber extends TypeSafeMatcher<Integer> {

    @Override
    protected boolean matchesSafely(Integer number) {
        return number > 1 && IntStream.rangeClosed(2, (int) Math.sqrt(number))
                .noneMatch(n -> (number % n == 0));
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("a prime number");
    }

    public static Matcher isPrimeNumber() {
        return new IsPrimeNumber();
    }
}

We create a custom matcher by extending the TypeSafeMatcher abstract class. We need to implement the matchSaely method which provides a predicate if the number is a prime number. We also implement describeTo method which produces a failure message in case a test fails.

Let’s test if a number is prime using our custom matcher isPrimeNumber:-

import static com.example.assertion.IsPrimeNumber.isPrimeNumber;

@Test
public void givenNumber_whenPrimeNumber_thenPass() {
    Integer num = 7;
    assertThat(num, new isPrimeNumber());
}

and here is a failure message when test a non-prime number:-

java.lang.AssertionError: Expected: a prime number but: was <8>

That’s all about the Hamcrest matchers. Thanks for Reading!