Writing Assertions With JUnit 5 and Hamcrest

If you want to learn how you can work smarter and save time when you are writing tests with JUnit 5, you should take a look at my Introduction to JUnit 5 course. It has 24 lessons, 47 exercises, and 13 quizzes.

This blog post describes how we can write assertions with Hamcrest when we are writing tests with JUnit 5. After we have finished this blog post, we:

  • Can get the required dependencies with Maven and Gradle.
  • Know how we can write basic assertions with Hamcrest.
  • Understand how we can combine multiple Hamcrest matchers.
  • Can customize the error message shown when an assertion fails.

Let's begin.

Getting the Required Dependencies

Before we can write assertions with Hamcrest, we have to ensure that the hamcrest-library dependency (version 2.2) is found from the classpath.

If we are using Maven, we have to add the hamcrest-library dependency to the test scope. We can do this by adding the following snippet to the dependencies section of our pom.xml file:

<dependency>
	<groupId>org.hamcrest</groupId>
	<artifactId>hamcrest-library</artifactId>
	<version>2.2</version>
	<scope>test</scope>
</dependency>

If we are using Gradle, we have to add the hamcrest-library dependency to the testImplementation dependency configuration. We can do this by adding the following snippet to our build.gradle file:

dependencies {
    testImplementation(
            'org.hamcrest:hamcrest-library:2.2'
    )
}

After we have ensured that the hamcrest-library dependency is found from the classpath, we can write assertions with Hamcrest. Let's find out how we can do it.

Writing Assertions With Hamcrest

If you have used Hamcrest with JUnit 4, you will probably remember that you had to use the assertThat() method of the org.junit.Assert class. However, the JUnit 5 API doesn't have a method that takes a Hamcrest matcher as a method parameter. The JUnit 5 User Guide explains this design decision as follows:

However, JUnit Jupiter's org.junit.jupiter.api.Assertions class does not provide an assertThat() method like the one found in JUnit 4's org.junit.Assert class which accepts a Hamcrest Matcher. Instead, developers are encouraged to use the built-in support for matchers provided by third-party assertion libraries.

In other words, if we want to use Hamcrest matchers, we have to use the assertThat() method of the org.hamcrest.MatcherAssert class. This method takes either two or three method parameters which are described in the following:

  1. An optional error message that's shown when our assertion fails.
  2. The actual value or object.
  3. A Matcher object that specifies the expected value. We can create new Matcher objects by using the static factory methods provided by the org.hamcrest.Matchers class.

Next, we will take a look at some examples which demonstrate how we can write assertions with Hamcrest. Let’s start by finding out how we can write assertions for boolean values.

Asserting Boolean Values

If we want to verify that a boolean value is true, we have to create our Hamcrest matcher by invoking the is() method of the Matchers class. In order words, we have to use this assertion:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

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

@DisplayName("Write assertions for booleans")
class BooleanAssertionTest {

    @Nested
    @DisplayName("When boolean is true")
    class WhenBooleanIsTrue {

        @Test
        @DisplayName("Should be true")
        void shouldBeTrue() {
            assertThat(true, is(true));
        }
    }
}

If we want to verify that a boolean value is false, we have to create our Hamcrest matcher by invoking the is() method of the Matchers class. In order words, we have to use this assertion:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

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

@DisplayName("Write assertions for booleans")
class BooleanAssertionTest {

    @Nested
    @DisplayName("When boolean is false")
    class WhenBooleanIsFalse {

        @Test
        @DisplayName("Should be false")
        void shouldBeFalse() {
            assertThat(false, is(false));
        }
    }
}

Let's move on and find out how we can verify that an object is null or isn't null.

Asserting That an Object Is Null or Isn't Null

If we want to verify that an object is null, we have to create our Hamcrest matcher by invoking the nullValue() method of the Matchers class. In order words, we have to use this assertion:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

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

@DisplayName("Writing assertions for objects")
class ObjectAssertionTest {

    @Nested
    @DisplayName("When object is null")
    class WhenObjectIsNull {

        @Test
        @DisplayName("Should be null")
        void shouldBeNull() {
            assertThat(null, nullValue());
        }
    }
}

If we want to verify that an object isn't null, we have to create our Hamcrest matcher by invoking the notNullValue() method of the Matchers class. In order words, we have to use this assertion:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

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

@DisplayName("Writing assertions for objects")
class ObjectAssertionTest {

    @Nested
    @DisplayName("When object is not null")
    class WhenObjectIsNotNotNull {

        @Test
        @DisplayName("Should not be null")
        void shouldNotBeNull() {
            assertThat(new Object(), notNullValue());
        }
    }
}

Next, we will find out how we can verify that two objects (or values) are equal or aren't equal.

Asserting That Two Objects or Values Are Equal

If we want to verify that the expected value (or object) is equal to the actual value (or object), we have to create our Hamcrest matcher by invoking the equalTo() method of the Matchers class. For example, if we want to compare two Integer objects, we have to use this assertion:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

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

@DisplayName("Writing assertions for objects")
class ObjectAssertionTest {

    @Nested
    @DisplayName("When two objects are equal")
    class WhenTwoObjectsAreEqual {

        @Nested
        @DisplayName("When objects are integers")
        class WhenObjectsAreIntegers {

            private final Integer ACTUAL = 9;
            private final Integer EXPECTED = 9;

            @Test
            @DisplayName("Should be equal")
            void shouldBeEqual() {
                assertThat(ACTUAL, equalTo(EXPECTED));
            }
        }
    }
}

If we want to verify that the expected value (or object) isn't equal to the actual value (or object), we have to create our Hamcrest matcher by invoking the not() method of the Matchers class. For example, if we want to compare two Integer objects, we have to use this assertion:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

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

@DisplayName("Writing assertions for objects")
class ObjectAssertionTest {

    @Nested
    @DisplayName("When two objects aren't equal")
    class WhenTwoObjectsAreNotEqual {

        @Nested
        @DisplayName("When objects are integers")
        class WhenObjectsAreIntegers {

            private final Integer ACTUAL = 9;
            private final Integer EXPECTED = 4;

            @Test
            @DisplayName("Should not be equal")
            void shouldNotBeEqual() {
                assertThat(ACTUAL, not(EXPECTED));
            }
        }
    }
}

Let's move on and find out how we can write assertions for object references.

Asserting Object References

If we want to ensure that two objects refer to the same object, we have to create our Hamcrest matcher by invoking the sameInstance() method of the Matchers class. In order words, we have to use this assertion:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

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

@DisplayName("Writing assertions for objects")
class ObjectAssertionTest {

    @Nested
    @DisplayName("When two objects refer to the same object")
    class WhenTwoObjectsReferToSameObject {

        private final Object ACTUAL = new Object();
        private final Object EXPECTED = ACTUAL;

        @Test
        @DisplayName("Should refer to the same object")
        void shouldReferToSameObject() {
            assertThat(ACTUAL, sameInstance(EXPECTED));
        }
    }
}

If we want to ensure that two objects don't refer to the same object, we have to reverse the expectation specified by the sameInstance() method by using the not() method of the Matchers class. In order words, we have to use this assertion:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.sameInstance;

@DisplayName("Writing assertions for objects")
class ObjectAssertionTest {

    @Nested
    @DisplayName("When two objects don't refer to the same object")
    class WhenTwoObjectsDoNotReferToSameObject {

        private final Object ACTUAL = new Object();
        private final Object EXPECTED = new Object();

        @Test
        @DisplayName("Should not refer to the same object")
        void shouldNotReferToSameObject() {
           assertThat(ACTUAL, not(sameInstance(EXPECTED)));
        }
    }
}
If you want to get access to up-to-date material which helps you to work smarter and save time when you are writing tests with JUnit 5, you should take a look at my Introduction to JUnit 5 course. It has 24 lessons, 47 exercises, and 13 quizzes.

Next, we will find out how we can verify that two arrays are equal.

Asserting That Two Arrays Are Equal

If we want to verify that two arrays are equal, we have to create our Hamcrest matcher by invoking the equalTo() method of the Matchers class. For example, if we want verify that two int arrays are equal, we have to use this assertion:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

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

@DisplayName("Write assertions for arrays")
class ArrayAssertionTest {

    @Nested
    @DisplayName("When arrays contain integers")
    class WhenArraysContainIntegers {

        final int[] ACTUAL = new int[]{2, 5, 7};
        final int[] EXPECTED = new int[]{2, 5, 7};

        @Test
        @DisplayName("Should contain the same integers")
        void shouldContainSameIntegers() {
            assertThat(ACTUAL, equalTo(EXPECTED));
        }
    }
}
Two arrays are considered as equal if:

  • They are both null or empty.
  • Both arrays contain the "same" objects or values. To be more specific, JUnit 5 iterates both arrays one element at a time and ensures that the elements found from the given index are equal.

Let's move on and find out how we can write assertions for lists.

Asserting Lists

If we want to write an assertion which verifies that the size of a list is correct, we have to create our Hamcrest matcher by invoking the hasSize() method of the Matchers class. For example, if we want to verify that the size of a list is 2, we have to use this assertion:

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;

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

@DisplayName("Writing assertions for lists")
class ListAssertionTest {

    @Nested
    @DisplayName("When we write assertions for elements")
    class WhenWeWriteAssertionsForElements {
        
        private Object first;
        private Object second;

        private List<Object> list;

        @BeforeEach
        void createAndInitializeList() {
            first = new Object();
            second = new Object();

            list = Arrays.asList(first, second);
        }

        @Test
        @DisplayName("Should contain two elements")
        void shouldContainTwoElements() {
            assertThat(list, hasSize(2));
        }
    }
}

If we want to verify that the list contains only the expected elements in the given order, we have to create our Hamcrest matcher by invoking the contains() method of the Matchers class. For example, if we want to verify that our list contains the correct elements in the given order, we have to use this assertion:

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;

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

@DisplayName("Writing assertions for lists")
class ListAssertionTest {

    @Nested
    @DisplayName("When we write assertions for elements")
    class WhenWeWriteAssertionsForElements {

        private Object first;
        private Object second;

        private List<Object> list;

        @BeforeEach
        void createAndInitializeList() {
            first = new Object();
            second = new Object();

            list = Arrays.asList(first, second);
        }

        @Test
        @DisplayName("Should contain the correct elements in the given order")
        void shouldContainCorrectElementsInGivenOrder() {
            assertThat(list, contains(first, second));
        }
    }
}

If we want to verify that the list contains only the expected elements in any order, we have to create our Hamcrest matcher by invoking the containsInAnyOrder() method of the Matchers class. For example, if we want to verify that our list contains the correct elements in any order, we have to use this assertion:

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;

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

@DisplayName("Writing assertions for lists")
class ListAssertionTest {

    @Nested
    @DisplayName("When we write assertions for elements")
    class WhenWeWriteAssertionsForElements {

        private Object first;
        private Object second;

        private List<Object> list;

        @BeforeEach
        void createAndInitializeList() {
            first = new Object();
            second = new Object();

            list = Arrays.asList(first, second);
        }

        @Test
        @DisplayName("Should contain the correct elements in any order")
        void shouldContainCorrectElementsInAnyOrder() {
            assertThat(list, containsInAnyOrder(second, first));
        }
    }
}

If we want to ensure that a list contains the given element, we have to create our Hamcrest matcher by invoking the hasItem() method of the Matchers class. For example, if we want to verify that our list contains the Object that's stored in the field called first, we have to use this assertion:

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;

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

@DisplayName("Writing assertions for lists")
class ListAssertionTest {

    @Nested
    @DisplayName("When we write assertions for elements")
    class WhenWeWriteAssertionsForElements {

        private Object first;
        private Object second;

        private List<Object> list;

        @BeforeEach
        void createAndInitializeList() {
            first = new Object();
            second = new Object();

            list = Arrays.asList(first, second);
        }

        @Test
        @DisplayName("Should contain a correct element")
        void shouldContainCorrectElement() {
            assertThat(list, hasItem(first));
        }
    }
}

If we want to ensure that a list doesn't contain an element, we have to reverse the expectation specified by the hasItem() method by using the not() method of the Matchers class. In order words, we have to use this assertion:

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.not;

@DisplayName("Writing assertions for lists")
class ListAssertionTest {

    @Nested
    @DisplayName("When we write assertions for elements")
    class WhenWeWriteAssertionsForElements {

        private Object first;
        private Object second;

        private List<Object> list;

        @BeforeEach
        void createAndInitializeList() {
            first = new Object();
            second = new Object();

            list = Arrays.asList(first, second);
        }

        @Test
        @DisplayName("Should not contain an incorrect element")
        void shouldNotContainIncorrectElement() {
            assertThat(list, not(hasItem(new Object())));
        }
    }
}

If we want to verify that two lists are deeply equal, we have to create our Hamcrest matcher by invoking the equalTo() method of the Matchers class. For example, if we want verify that two Integer lists are deeply equal, we have to use this assertion:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;

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

@DisplayName("Writing assertions for lists")
class ListAssertionTest {

    @Nested
    @DisplayName("When we compare two lists")
    class WhenWeCompareTwoLists {

        private final List<Integer> ACTUAL = Arrays.asList(1, 2, 3);
        private final List<Integer> EXPECTED = Arrays.asList(1, 2, 3);

        @Test
        @DisplayName("Should contain the same elements")
        void shouldContainSameElements() {
            assertThat(ACTUAL, equalTo(EXPECTED));
        }
    }
}
Two lists are considered as equal if:

  • They are both null or empty.
  • Both lists contain the "same" objects or values. To be more specific, JUnit 5 iterates both lists one element at a time and ensures that the elements found from the given index are equal.

Next, we will find out how we can write assertions for maps.

Asserting Maps

If we want to verify that a map contains the given key, we have to create our Hamcrest matcher by invoking the hasKey() method of the Matchers class. In other words, we have to use this assertion:

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import java.util.HashMap;
import java.util.Map;

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

@DisplayName("Writing assertions for maps")
class MapAssertionTest {
    
    private static final String KEY = "key";
    private static final String VALUE = "value";

    private Map<String, String> map;

    @BeforeEach
    void createAndInitializeMap() {
        map = new HashMap<>();
        map.put(KEY, VALUE);
    }

    @Nested
    @DisplayName("When we check if the map contains the given key")
    class WhenWeCheckIfMapContainsGivenKey {

        @Test
        @DisplayName("Should contain the correct key")
        void shouldContainCorrectKey() {
            assertThat(map, hasKey(KEY));
        }
    }
}

If we want to verify that a map doesn't contain the given key, we have to reverse the expectation specified by the hasKey() method by using the not() method of the Matchers class. In other words, we have to use this assertion:

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import java.util.HashMap;
import java.util.Map;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasKey;
import static org.hamcrest.Matchers.not;

@DisplayName("Writing assertions for maps")
class MapAssertionTest {

    private static final String INCORRECT_KEY = "incorrectKey";
    private static final String KEY = "key";
    private static final String VALUE = "value";

    private Map<String, String> map;

    @BeforeEach
    void createAndInitializeMap() {
        map = new HashMap<>();
        map.put(KEY, VALUE);
    }

    @Nested
    @DisplayName("When we check if the map contains the given key")
    class WhenWeCheckIfMapContainsGivenKey {

        @Test
        @DisplayName("Should not contain the incorrect key")
        void shouldNotContainIncorrectKey() {
            assertThat(map, not(hasKey(INCORRECT_KEY)));
        }
    }
}

If we want to ensure that a map contains the correct value, we have to create our Hamcrest matcher by invoking the hasEntry() method of the Matchers class. In other words, we have to use this assertion:

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import java.util.HashMap;
import java.util.Map;

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

@DisplayName("Writing assertions for maps")
class MapAssertionTest {
    
    private static final String KEY = "key";
    private static final String VALUE = "value";

    private Map<String, String> map;

    @BeforeEach
    void createAndInitializeMap() {
        map = new HashMap<>();
        map.put(KEY, VALUE);
    }

    @Nested
    @DisplayName("When we check if the map contains the correct value")
    class WhenWeCheckIfMapContainsCorrectValue {

        @Test
        @DisplayName("Should contain the correct value")
        void shouldContainCorrectValue() {
            assertThat(map, hasEntry(KEY, VALUE));
        }
    }
}

Let's move on and find out how we can combine multiple Hamcrest matchers.

Combining Hamcrest Matchers

We can now write basic assertions with Hamcrest. However, sometimes we have to combine multiple Hamcrest matchers. In fact, we already did this when we reversed the expectation of a Hamcrest matcher by invoking the not() method of the Matchers class.

Next, we will take a look at two examples which demonstrate how we can combine Hamcrest matchers when we are writing assertions for a Person object. The source code of the Person class looks as follows:

public class Person {
 
    private String firstName;
    private String lastName;
 
    public Person() {}
 
    public String getFirstName() {
        return firstName;
    }
 
    public String getLastName() {
        return lastName;
    }
 
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
 
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}

As we can see, if we want to verify that a person has the correct name, we have to ensure that the asserted Person object has the correct first and last name. When we write this assertion, we have to create the Hamcrest matcher that's passed to the assertThat() method by using these Hamcrest Matchers:

  • The allOf() method of the Matchers class returns a Hamcrest matcher which expects that the asserted object matches with all specified Hamcrest matchers.
  • The hasProperty() method of the Matchers class returns a matcher which allows us to write assertions for the properties of the asserted object.
  • The equalTo() method of the Matchers class returns a matcher which allows us to verify that the actual property value is equal to the expected value.

After we have written our assertion, it looks as follows:

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasProperty;

@DisplayName("Combine multiple assertions")
class CombineAssertionsTest {

    private static final String FIRST_NAME = "Jane";
    private static final String LAST_NAME = "Doe";

    private Person person;

    @BeforeEach
    void createPerson() {
        person = new Person();
        person.setFirstName(FIRST_NAME);
        person.setLastName(LAST_NAME);
    }

    @Test
    @DisplayName("Should have the correct name")
    void shouldHaveCorrectName() {
        assertThat(person, allOf(
                hasProperty("firstName", equalTo(FIRST_NAME)),
                hasProperty("lastName", equalTo(LAST_NAME))
        ));
    }
}

On the other hand, if we want to verify that a person has the correct first name or last name, we have to create the Hamcrest matcher that's passed to the assertThat() method by using these Hamcrest Matchers:

  • The anyOf() method of the Matchers class returns a Hamcrest matcher which expects that the asserted object matches with any specified Hamcrest matcher.
  • The hasProperty() method of the Matchers class returns a matcher which allows us to write assertions for the properties of the asserted object.
  • The equalTo() method of the Matchers class returns a matcher which allows us to verify that the actual property value is equal to the expected value.

After we have written our assertion, it looks as follows:

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasProperty;

@DisplayName("Combine multiple assertions")
class CombineAssertionsTest {

    private static final String FIRST_NAME = "Jane";
    private static final String LAST_NAME = "Doe";

    private Person person;

    @BeforeEach
    void createPerson() {
        person = new Person();
        person.setFirstName(FIRST_NAME);
        person.setLastName(LAST_NAME);
    }

    @Test
    @DisplayName("Should have correct first name or last name")
    void shouldHaveCorrectFirstNameOrLastName() {
        assertThat(person, anyOf(
                hasProperty("firstName", equalTo(FIRST_NAME)),
                hasProperty("lastName", equalTo(LAST_NAME))
        ));
    }
}
Quite many factory methods provided by the Matchers class can take a Hamcrest matcher (or matchers) as a method parameter. That's why I recommend that you take a look at its documentation when it seems that you cannot write the assertion you need. The odds are that you can write it by combining multiple Hamcrest matchers.

Next, we will find out how we can provide a custom error message that's shown when our assertion fails.

Providing a Custom Error Message

As we remember, if we want to specify a custom error message that's shown when our assertion fails, we have to pass this message as the first method parameter of the assertThat() method. We can create this error message by using one of these two options:

  • If the error message has no parameters, we should use a String literal.
  • If the error message has parameters, we should use the static format() method of the String class.

For example, if we want to create an error message that's shown when the asserted list doesn't contain the given element, we have to create an assertion that looks as follows:

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;

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

@DisplayName("Writing assertions for lists")
class ListAssertionTest {

    @Nested
    @DisplayName("When we write assertions for elements")
    class WhenWeWriteAssertionsForElements {

        private Object first;
        private Object second;

        private List<Object> list;

        @BeforeEach
        void createAndInitializeList() {
            first = new Object();
            second = new Object();

            list = Arrays.asList(first, second);
        }

        @Test
        @DisplayName("Should contain a correct element")
        void shouldContainCorrectElementWithCustomErrorMessage() {
            assertThat(String.format(
                            "The list doesn't contain the expected object: %s", 
                            first
                    ),
                    list,
                    hasItem(first)
            );
        }
    }
}
It's good to understand that the custom error message doesn't override the default error message shown if an assertion fails. It is simply a prefix that's prepended to the default error message of the used Hamcrest matcher. At first, this feels a bit weird, but it’s actually quite useful after you get used to it.

We can now write basic assertions with Hamcrest, combine multiple Hamcrest matchers, and provide a custom error message that's shown when an assertion fails.

Let's summarize what we learned from this blog post.

Summary

This blog post has taught us four things:

  • Before we can write assertions with Hamcrest, we have to ensure that the hamcrest-library dependency is found from the classpath.
  • If we want to write assertions with Hamcrest, we have to use the assertThat() method of the org.hamcrest.MatcherAssert class.
  • If we want to provide a custom error message that's shown when an assertion fails, we have to pass this error message as the first method parameter of the assertThat() method.
  • Some methods of the Matchers class can take a Hamcrest matcher (or matchers) as a method parameter. We can combine multiple Hamcrest matchers by using these methods.

P.S. You can get the example application of this blog post from Github

2 comments… add one
  • Ketan Dec 13, 2018 @ 19:15

    Is there an easy way for asserting all fields of object (via getters) are not null ?

    • Petri Dec 13, 2018 @ 22:08

      If you want to use Hamcrest, you can combine multiple assertions by using the allOf() method of the Matchers. Also, because you want to ensure that all field values of your object are null, you have to write the actual assertions by using the nullValue() method of the Matchers class.

      That being said, I think that you should take a look at AssertJ. It allows you to write so called soft assertions that help you to solve your problem in a elegant way.

      The difference between these two methods is that AssertJ runs all assertions (if you use soft assertions) before it reports the results. In other words, if a test case fails, you can see all assertions failures. If you use Hamcrest, you can see only the first assertion failure. This means that you might have to run your test case multiple times (and fix your code) before it passes.

Leave a Reply