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:

1<dependency>
2	<groupId>org.hamcrest</groupId>
3	<artifactId>hamcrest-library</artifactId>
4	<version>2.2</version>
5	<scope>test</scope>
6</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:

1dependencies {
2    testImplementation(
3            'org.hamcrest:hamcrest-library:2.2'
4    )
5}

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:

 1import org.junit.jupiter.api.DisplayName;
 2import org.junit.jupiter.api.Nested;
 3import org.junit.jupiter.api.Test;
 4
 5import static org.hamcrest.Matchers.is;
 6import static org.hamcrest.MatcherAssert.assertThat;
 7
 8@DisplayName("Write assertions for booleans")
 9class BooleanAssertionTest {
10
11    @Nested
12    @DisplayName("When boolean is true")
13    class WhenBooleanIsTrue {
14
15        @Test
16        @DisplayName("Should be true")
17        void shouldBeTrue() {
18            assertThat(true, is(true));
19        }
20    }
21}

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:

 1import org.junit.jupiter.api.DisplayName;
 2import org.junit.jupiter.api.Nested;
 3import org.junit.jupiter.api.Test;
 4
 5import static org.hamcrest.Matchers.is;
 6import static org.hamcrest.MatcherAssert.assertThat;
 7
 8@DisplayName("Write assertions for booleans")
 9class BooleanAssertionTest {
10
11    @Nested
12    @DisplayName("When boolean is false")
13    class WhenBooleanIsFalse {
14
15        @Test
16        @DisplayName("Should be false")
17        void shouldBeFalse() {
18            assertThat(false, is(false));
19        }
20    }
21}

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:

 1import org.junit.jupiter.api.DisplayName;
 2import org.junit.jupiter.api.Nested;
 3import org.junit.jupiter.api.Test;
 4
 5import static org.hamcrest.MatcherAssert.assertThat;
 6import static org.hamcrest.Matchers.nullValue;
 7
 8@DisplayName("Writing assertions for objects")
 9class ObjectAssertionTest {
10
11    @Nested
12    @DisplayName("When object is null")
13    class WhenObjectIsNull {
14
15        @Test
16        @DisplayName("Should be null")
17        void shouldBeNull() {
18            assertThat(null, nullValue());
19        }
20    }
21}

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:

 1import org.junit.jupiter.api.DisplayName;
 2import org.junit.jupiter.api.Nested;
 3import org.junit.jupiter.api.Test;
 4
 5import static org.hamcrest.MatcherAssert.assertThat;
 6import static org.hamcrest.Matchers.notNullValue;
 7
 8@DisplayName("Writing assertions for objects")
 9class ObjectAssertionTest {
10
11    @Nested
12    @DisplayName("When object is not null")
13    class WhenObjectIsNotNotNull {
14
15        @Test
16        @DisplayName("Should not be null")
17        void shouldNotBeNull() {
18            assertThat(new Object(), notNullValue());
19        }
20    }
21}

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:

 1import org.junit.jupiter.api.DisplayName;
 2import org.junit.jupiter.api.Nested;
 3import org.junit.jupiter.api.Test;
 4
 5import static org.hamcrest.MatcherAssert.assertThat;
 6import static org.hamcrest.Matchers.equalTo;
 7
 8@DisplayName("Writing assertions for objects")
 9class ObjectAssertionTest {
10
11    @Nested
12    @DisplayName("When two objects are equal")
13    class WhenTwoObjectsAreEqual {
14
15        @Nested
16        @DisplayName("When objects are integers")
17        class WhenObjectsAreIntegers {
18
19            private final Integer ACTUAL = 9;
20            private final Integer EXPECTED = 9;
21
22            @Test
23            @DisplayName("Should be equal")
24            void shouldBeEqual() {
25                assertThat(ACTUAL, equalTo(EXPECTED));
26            }
27        }
28    }
29}

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:

 1import org.junit.jupiter.api.DisplayName;
 2import org.junit.jupiter.api.Nested;
 3import org.junit.jupiter.api.Test;
 4
 5import static org.hamcrest.MatcherAssert.assertThat;
 6import static org.hamcrest.Matchers.not;
 7
 8@DisplayName("Writing assertions for objects")
 9class ObjectAssertionTest {
10
11    @Nested
12    @DisplayName("When two objects aren't equal")
13    class WhenTwoObjectsAreNotEqual {
14
15        @Nested
16        @DisplayName("When objects are integers")
17        class WhenObjectsAreIntegers {
18
19            private final Integer ACTUAL = 9;
20            private final Integer EXPECTED = 4;
21
22            @Test
23            @DisplayName("Should not be equal")
24            void shouldNotBeEqual() {
25                assertThat(ACTUAL, not(EXPECTED));
26            }
27        }
28    }
29}

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:

 1import org.junit.jupiter.api.DisplayName;
 2import org.junit.jupiter.api.Nested;
 3import org.junit.jupiter.api.Test;
 4
 5import static org.hamcrest.MatcherAssert.assertThat;
 6import static org.hamcrest.Matchers.sameInstance;
 7
 8@DisplayName("Writing assertions for objects")
 9class ObjectAssertionTest {
10
11    @Nested
12    @DisplayName("When two objects refer to the same object")
13    class WhenTwoObjectsReferToSameObject {
14
15        private final Object ACTUAL = new Object();
16        private final Object EXPECTED = ACTUAL;
17
18        @Test
19        @DisplayName("Should refer to the same object")
20        void shouldReferToSameObject() {
21            assertThat(ACTUAL, sameInstance(EXPECTED));
22        }
23    }
24}

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:

 1import org.junit.jupiter.api.DisplayName;
 2import org.junit.jupiter.api.Nested;
 3import org.junit.jupiter.api.Test;
 4
 5import static org.hamcrest.MatcherAssert.assertThat;
 6import static org.hamcrest.Matchers.not;
 7import static org.hamcrest.Matchers.sameInstance;
 8
 9@DisplayName("Writing assertions for objects")
10class ObjectAssertionTest {
11
12    @Nested
13    @DisplayName("When two objects don't refer to the same object")
14    class WhenTwoObjectsDoNotReferToSameObject {
15
16        private final Object ACTUAL = new Object();
17        private final Object EXPECTED = new Object();
18
19        @Test
20        @DisplayName("Should not refer to the same object")
21        void shouldNotReferToSameObject() {
22           assertThat(ACTUAL, not(sameInstance(EXPECTED)));
23        }
24    }
25}

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:

 1import org.junit.jupiter.api.DisplayName;
 2import org.junit.jupiter.api.Nested;
 3import org.junit.jupiter.api.Test;
 4
 5import static org.hamcrest.Matchers.equalTo;
 6import static org.hamcrest.MatcherAssert.assertThat;
 7
 8@DisplayName("Write assertions for arrays")
 9class ArrayAssertionTest {
10
11    @Nested
12    @DisplayName("When arrays contain integers")
13    class WhenArraysContainIntegers {
14
15        final int[] ACTUAL = new int[]{2, 5, 7};
16        final int[] EXPECTED = new int[]{2, 5, 7};
17
18        @Test
19        @DisplayName("Should contain the same integers")
20        void shouldContainSameIntegers() {
21            assertThat(ACTUAL, equalTo(EXPECTED));
22        }
23    }
24}

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:

 1import org.junit.jupiter.api.BeforeEach;
 2import org.junit.jupiter.api.DisplayName;
 3import org.junit.jupiter.api.Nested;
 4import org.junit.jupiter.api.Test;
 5
 6import java.util.Arrays;
 7import java.util.List;
 8
 9import static org.hamcrest.MatcherAssert.assertThat;
10import static org.hamcrest.Matchers.hasSize;
11
12@DisplayName("Writing assertions for lists")
13class ListAssertionTest {
14
15    @Nested
16    @DisplayName("When we write assertions for elements")
17    class WhenWeWriteAssertionsForElements {
18
19        private Object first;
20        private Object second;
21
22        private List<Object> list;
23
24        @BeforeEach
25        void createAndInitializeList() {
26            first = new Object();
27            second = new Object();
28
29            list = Arrays.asList(first, second);
30        }
31
32        @Test
33        @DisplayName("Should contain two elements")
34        void shouldContainTwoElements() {
35            assertThat(list, hasSize(2));
36        }
37    }
38}

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:

 1import org.junit.jupiter.api.BeforeEach;
 2import org.junit.jupiter.api.DisplayName;
 3import org.junit.jupiter.api.Nested;
 4import org.junit.jupiter.api.Test;
 5
 6import java.util.Arrays;
 7import java.util.List;
 8
 9import static org.hamcrest.MatcherAssert.assertThat;
10import static org.hamcrest.Matchers.contains;
11
12@DisplayName("Writing assertions for lists")
13class ListAssertionTest {
14
15    @Nested
16    @DisplayName("When we write assertions for elements")
17    class WhenWeWriteAssertionsForElements {
18
19        private Object first;
20        private Object second;
21
22        private List<Object> list;
23
24        @BeforeEach
25        void createAndInitializeList() {
26            first = new Object();
27            second = new Object();
28
29            list = Arrays.asList(first, second);
30        }
31
32        @Test
33        @DisplayName("Should contain the correct elements in the given order")
34        void shouldContainCorrectElementsInGivenOrder() {
35            assertThat(list, contains(first, second));
36        }
37    }
38}

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:

 1import org.junit.jupiter.api.BeforeEach;
 2import org.junit.jupiter.api.DisplayName;
 3import org.junit.jupiter.api.Nested;
 4import org.junit.jupiter.api.Test;
 5
 6import java.util.Arrays;
 7import java.util.List;
 8
 9import static org.hamcrest.MatcherAssert.assertThat;
10import static org.hamcrest.Matchers.containsInAnyOrder;
11
12@DisplayName("Writing assertions for lists")
13class ListAssertionTest {
14
15    @Nested
16    @DisplayName("When we write assertions for elements")
17    class WhenWeWriteAssertionsForElements {
18
19        private Object first;
20        private Object second;
21
22        private List<Object> list;
23
24        @BeforeEach
25        void createAndInitializeList() {
26            first = new Object();
27            second = new Object();
28
29            list = Arrays.asList(first, second);
30        }
31
32        @Test
33        @DisplayName("Should contain the correct elements in any order")
34        void shouldContainCorrectElementsInAnyOrder() {
35            assertThat(list, containsInAnyOrder(second, first));
36        }
37    }
38}

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:

 1import org.junit.jupiter.api.BeforeEach;
 2import org.junit.jupiter.api.DisplayName;
 3import org.junit.jupiter.api.Nested;
 4import org.junit.jupiter.api.Test;
 5
 6import java.util.Arrays;
 7import java.util.List;
 8
 9import static org.hamcrest.MatcherAssert.assertThat;
10import static org.hamcrest.Matchers.hasItem;
11
12@DisplayName("Writing assertions for lists")
13class ListAssertionTest {
14
15    @Nested
16    @DisplayName("When we write assertions for elements")
17    class WhenWeWriteAssertionsForElements {
18
19        private Object first;
20        private Object second;
21
22        private List<Object> list;
23
24        @BeforeEach
25        void createAndInitializeList() {
26            first = new Object();
27            second = new Object();
28
29            list = Arrays.asList(first, second);
30        }
31
32        @Test
33        @DisplayName("Should contain a correct element")
34        void shouldContainCorrectElement() {
35            assertThat(list, hasItem(first));
36        }
37    }
38}

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:

 1import org.junit.jupiter.api.BeforeEach;
 2import org.junit.jupiter.api.DisplayName;
 3import org.junit.jupiter.api.Nested;
 4import org.junit.jupiter.api.Test;
 5
 6import java.util.Arrays;
 7import java.util.List;
 8
 9import static org.hamcrest.MatcherAssert.assertThat;
10import static org.hamcrest.Matchers.hasItem;
11import static org.hamcrest.Matchers.not;
12
13@DisplayName("Writing assertions for lists")
14class ListAssertionTest {
15
16    @Nested
17    @DisplayName("When we write assertions for elements")
18    class WhenWeWriteAssertionsForElements {
19
20        private Object first;
21        private Object second;
22
23        private List<Object> list;
24
25        @BeforeEach
26        void createAndInitializeList() {
27            first = new Object();
28            second = new Object();
29
30            list = Arrays.asList(first, second);
31        }
32
33        @Test
34        @DisplayName("Should not contain an incorrect element")
35        void shouldNotContainIncorrectElement() {
36            assertThat(list, not(hasItem(new Object())));
37        }
38    }
39}

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:

 1import org.junit.jupiter.api.DisplayName;
 2import org.junit.jupiter.api.Nested;
 3import org.junit.jupiter.api.Test;
 4
 5import java.util.Arrays;
 6import java.util.List;
 7
 8import static org.hamcrest.MatcherAssert.assertThat;
 9import static org.hamcrest.Matchers.equalTo;
10
11@DisplayName("Writing assertions for lists")
12class ListAssertionTest {
13
14    @Nested
15    @DisplayName("When we compare two lists")
16    class WhenWeCompareTwoLists {
17
18        private final List<Integer> ACTUAL = Arrays.asList(1, 2, 3);
19        private final List<Integer> EXPECTED = Arrays.asList(1, 2, 3);
20
21        @Test
22        @DisplayName("Should contain the same elements")
23        void shouldContainSameElements() {
24            assertThat(ACTUAL, equalTo(EXPECTED));
25        }
26    }
27}

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:

 1import org.junit.jupiter.api.BeforeEach;
 2import org.junit.jupiter.api.DisplayName;
 3import org.junit.jupiter.api.Nested;
 4import org.junit.jupiter.api.Test;
 5
 6import java.util.HashMap;
 7import java.util.Map;
 8
 9import static org.hamcrest.MatcherAssert.assertThat;
10import static org.hamcrest.Matchers.hasKey;
11
12@DisplayName("Writing assertions for maps")
13class MapAssertionTest {
14
15    private static final String KEY = "key";
16    private static final String VALUE = "value";
17
18    private Map<String, String> map;
19
20    @BeforeEach
21    void createAndInitializeMap() {
22        map = new HashMap<>();
23        map.put(KEY, VALUE);
24    }
25
26    @Nested
27    @DisplayName("When we check if the map contains the given key")
28    class WhenWeCheckIfMapContainsGivenKey {
29
30        @Test
31        @DisplayName("Should contain the correct key")
32        void shouldContainCorrectKey() {
33            assertThat(map, hasKey(KEY));
34        }
35    }
36}

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:

 1import org.junit.jupiter.api.BeforeEach;
 2import org.junit.jupiter.api.DisplayName;
 3import org.junit.jupiter.api.Nested;
 4import org.junit.jupiter.api.Test;
 5
 6import java.util.HashMap;
 7import java.util.Map;
 8
 9import static org.hamcrest.MatcherAssert.assertThat;
10import static org.hamcrest.Matchers.hasKey;
11import static org.hamcrest.Matchers.not;
12
13@DisplayName("Writing assertions for maps")
14class MapAssertionTest {
15
16    private static final String INCORRECT_KEY = "incorrectKey";
17    private static final String KEY = "key";
18    private static final String VALUE = "value";
19
20    private Map<String, String> map;
21
22    @BeforeEach
23    void createAndInitializeMap() {
24        map = new HashMap<>();
25        map.put(KEY, VALUE);
26    }
27
28    @Nested
29    @DisplayName("When we check if the map contains the given key")
30    class WhenWeCheckIfMapContainsGivenKey {
31
32        @Test
33        @DisplayName("Should not contain the incorrect key")
34        void shouldNotContainIncorrectKey() {
35            assertThat(map, not(hasKey(INCORRECT_KEY)));
36        }
37    }
38}

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:

 1import org.junit.jupiter.api.BeforeEach;
 2import org.junit.jupiter.api.DisplayName;
 3import org.junit.jupiter.api.Nested;
 4import org.junit.jupiter.api.Test;
 5
 6import java.util.HashMap;
 7import java.util.Map;
 8
 9import static org.hamcrest.MatcherAssert.assertThat;
10import static org.hamcrest.Matchers.hasEntry;
11
12@DisplayName("Writing assertions for maps")
13class MapAssertionTest {
14
15    private static final String KEY = "key";
16    private static final String VALUE = "value";
17
18    private Map<String, String> map;
19
20    @BeforeEach
21    void createAndInitializeMap() {
22        map = new HashMap<>();
23        map.put(KEY, VALUE);
24    }
25
26    @Nested
27    @DisplayName("When we check if the map contains the correct value")
28    class WhenWeCheckIfMapContainsCorrectValue {
29
30        @Test
31        @DisplayName("Should contain the correct value")
32        void shouldContainCorrectValue() {
33            assertThat(map, hasEntry(KEY, VALUE));
34        }
35    }
36}

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:

 1public class Person {
 2
 3    private String firstName;
 4    private String lastName;
 5
 6    public Person() {}
 7
 8    public String getFirstName() {
 9        return firstName;
10    }
11
12    public String getLastName() {
13        return lastName;
14    }
15
16    public void setFirstName(String firstName) {
17        this.firstName = firstName;
18    }
19
20    public void setLastName(String lastName) {
21        this.lastName = lastName;
22    }
23}

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:

 1import org.junit.jupiter.api.BeforeEach;
 2import org.junit.jupiter.api.DisplayName;
 3import org.junit.jupiter.api.Test;
 4
 5import static org.hamcrest.MatcherAssert.assertThat;
 6import static org.hamcrest.Matchers.allOf;
 7import static org.hamcrest.Matchers.equalTo;
 8import static org.hamcrest.Matchers.hasProperty;
 9
10@DisplayName("Combine multiple assertions")
11class CombineAssertionsTest {
12
13    private static final String FIRST_NAME = "Jane";
14    private static final String LAST_NAME = "Doe";
15
16    private Person person;
17
18    @BeforeEach
19    void createPerson() {
20        person = new Person();
21        person.setFirstName(FIRST_NAME);
22        person.setLastName(LAST_NAME);
23    }
24
25    @Test
26    @DisplayName("Should have the correct name")
27    void shouldHaveCorrectName() {
28        assertThat(person, allOf(
29                hasProperty("firstName", equalTo(FIRST_NAME)),
30                hasProperty("lastName", equalTo(LAST_NAME))
31        ));
32    }
33}

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:

 1import org.junit.jupiter.api.BeforeEach;
 2import org.junit.jupiter.api.DisplayName;
 3import org.junit.jupiter.api.Test;
 4
 5import static org.hamcrest.MatcherAssert.assertThat;
 6import static org.hamcrest.Matchers.anyOf;
 7import static org.hamcrest.Matchers.equalTo;
 8import static org.hamcrest.Matchers.hasProperty;
 9
10@DisplayName("Combine multiple assertions")
11class CombineAssertionsTest {
12
13    private static final String FIRST_NAME = "Jane";
14    private static final String LAST_NAME = "Doe";
15
16    private Person person;
17
18    @BeforeEach
19    void createPerson() {
20        person = new Person();
21        person.setFirstName(FIRST_NAME);
22        person.setLastName(LAST_NAME);
23    }
24
25    @Test
26    @DisplayName("Should have correct first name or last name")
27    void shouldHaveCorrectFirstNameOrLastName() {
28        assertThat(person, anyOf(
29                hasProperty("firstName", equalTo(FIRST_NAME)),
30                hasProperty("lastName", equalTo(LAST_NAME))
31        ));
32    }
33}
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:

 1import org.junit.jupiter.api.BeforeEach;
 2import org.junit.jupiter.api.DisplayName;
 3import org.junit.jupiter.api.Nested;
 4import org.junit.jupiter.api.Test;
 5
 6import java.util.Arrays;
 7import java.util.List;
 8
 9import static org.hamcrest.MatcherAssert.assertThat;
10import static org.hamcrest.Matchers.hasItem;
11
12@DisplayName("Writing assertions for lists")
13class ListAssertionTest {
14
15    @Nested
16    @DisplayName("When we write assertions for elements")
17    class WhenWeWriteAssertionsForElements {
18
19        private Object first;
20        private Object second;
21
22        private List<Object> list;
23
24        @BeforeEach
25        void createAndInitializeList() {
26            first = new Object();
27            second = new Object();
28
29            list = Arrays.asList(first, second);
30        }
31
32        @Test
33        @DisplayName("Should contain a correct element")
34        void shouldContainCorrectElementWithCustomErrorMessage() {
35            assertThat(String.format(
36                            "The list doesn't contain the expected object: %s",
37                            first
38                    ),
39                    list,
40                    hasItem(first)
41            );
42        }
43    }
44}
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