Writing Assertions With JUnit 4 and Hamcrest

After we have finished this lesson, we

  • Can write assertions with JUnit 4 and Hamcrest.
  • Understand when we should write our assertions with Hamcrest.

Getting the Required Dependencies

Before we can write assertions with Hamcrest, we have to get the required dependencies. We can do this by declaring the hamcrest-library dependency (version 1.3) in our build script.

If we are using Maven, we can declare this dependency by adding the following snippet into our pom.xml file:

1<dependency>
2	<groupId>org.hamcrest</groupId>
3	<artifactId>hamcrest-library</artifactId>
4	<version>1.3</version>
5	<scope>test</scope>
6</dependency>

If we are using Gradle, we can declare this dependency by adding the following snippet into our build.gradle file:

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

After we have added this dependency into our build script, we can start writing assertions with JUnit 4 and Hamcrest.

Writing Assertions With Hamcrest

When we want to write assertions with Hamcrest, we have to use the assertThat() method of the org.junit.Assert class. This method can take three method parameters. These method parameters are described in the following:

  1. This is an optional method parameter and it contains the error message that is shown when our assertion fails.
  2. The actual value or object.
  3. The Hamcrest matcher that is used to specify the expected value.

Let’s move on and take a look at examples which demonstrate how we can write assertions with JUnit 4 and Hamcrest.

Asserting Boolean Values

If we want to verify that a boolean value is true, we can create the correct Hamcrest matcher by invoking the is() method of the Matchers class. In order words, we can use one of these two assertions:

 1import org.junit.Test;
 2
 3import static org.hamcrest.Matchers.is;
 4import static org.junit.Assert.assertThat;
 5
 6public class BooleanAssertionTest {
 7
 8    private static final boolean TRUE = true;
 9
10    @Test
11    public void booleanShouldBeTrue() {
12        assertThat(TRUE, is(true));
13        assertThat("Expected boolean to be true but was false",
14				TRUE,
15				is(true)
16		);
17    }
18}

If we want to verify that a boolean value is false, we can create the correct Hamcrest matcher by invoking the is() method of the Matchers class. In order words, we can use one of these two assertions:

 1import org.junit.Test;
 2
 3import static org.hamcrest.Matchers.is;
 4import static org.junit.Assert.assertThat;
 5
 6public class BooleanAssertionTest {
 7
 8    private static final boolean FALSE = false;
 9
10    @Test
11    public void booleanShouldBeFalse() {
12        assertThat(FALSE, is(false));
13        assertThat("Expected boolean to be false but was true",
14				FALSE,
15				is(false)
16		);
17    }
18}

Asserting That an Object Is Null or Is Not Null

If we want to verify that an object is null, we can create the correct Hamcrest matcher by invoking the nullValue() method of the Matchers class. In order words, we can use one of these two assertions:

 1import org.junit.Test;
 2
 3import static org.hamcrest.Matchers.nullValue;
 4import static org.junit.Assert.assertThat;
 5
 6public class ObjectAssertionTest {
 7
 8    @Test
 9    public void objectShouldBeNull() {
10        Object actual = null;
11
12        assertThat(actual, nullValue());
13        assertThat(String.format("Expected object to be null but was: %s",
14						actual
15				),
16                actual,
17                nullValue()
18        );
19    }
20}

If we want to verify that an object is not null, we can create the correct Hamcrest matcher by invoking the notNullValue() method of the Matchers class. In order words, we can use one of these two assertions:

 1import org.junit.Test;
 2
 3import static org.hamcrest.Matchers.notNullValue;
 4import static org.junit.Assert.assertThat;
 5
 6public class ObjectAssertionTest {
 7
 8    @Test
 9    public void objectShouldNotBeNull() {
10        Object actual = new Object();
11
12        assertThat(actual, notNullValue());
13        assertThat("Expected object to be not null but was null",
14				actual,
15				notNullValue()
16		);
17    }
18}

Asserting the Equality of Two Values or Objects

If we want to verify that the expected value (or object) is equal to the actual value (or object), we can create the correct Hamcrest matcher by invoking the is() method of the Matchers class. For example, if we want to compare two Integer objects, we can use one of these two assertions:

 1import org.junit.Test;
 2
 3import static org.hamcrest.Matchers.is;
 4import static org.junit.Assert.assertThat;
 5
 6public class ObjectAssertionTest {
 7
 8    @Test
 9    public void twoIntegersShouldBeEqual() {
10        Integer actual = 9;
11        Integer expected = 9;
12
13        assertThat(actual, is(expected));
14        assertThat(String.format(
15						"Expected integer to be: %d but was: %d",
16						expected,
17						actual
18				),
19                actual,
20                is(expected)
21        );
22    }
23}

If we want to verify that the expected value (or object) is not equal to the actual value (or object), we can create the correct Hamcrest matcher by invoking the not() method of the Matchers class. For example, if we want to compare two Integer objects, we can use one of these two assertions:

 1import org.junit.Test;
 2
 3import static org.hamcrest.Matchers.not;
 4import static org.junit.Assert.assertThat;
 5
 6public class ObjectAssertionTest {
 7
 8    @Test
 9    public void twoIntegersShouldNotBeEqual() {
10        Integer actual = 9;
11        Integer expected = 41;
12
13        assertThat(actual, not(expected));
14        assertThat(String.format(
15						"Expected integer to not be: %d but was: %d",
16						expected,
17						actual
18				),
19                actual,
20                not(expected)
21        );
22    }
23}

Asserting Object References

If we want to assert that two objects refer to the same object, we can create the correct Hamcrest matcher by invoking the sameInstance method of the Matchers class. In other words, we can use one of these two assertions:

 1import org.junit.Test;
 2
 3import static org.hamcrest.Matchers.sameInstance;
 4import static org.junit.Assert.assertThat;
 5
 6public class ObjectAssertionTest {
 7
 8    @Test
 9    public void shouldPointToSameObject() {
10        Object actual = new Object();
11        Object expected = actual;
12
13        assertThat(actual, sameInstance(expected));
14        assertThat("Expected two objects to be the same but they are not",
15                actual,
16                sameInstance(expected)
17        );
18    }
19}
Unfortunately the Matchers class has no method that can be used for writing an assertion that verifies that two objects do not refer to the same object. If you want do this, you can either create a custom Hamcrest matcher or use the standard JUnit 4 assertions .

Asserting the Equality of Two Arrays

If we want to verify that two arrays are equal, we can create the correct Hamcrest matcher by invoking the is() method of the Matchers class. For example, if we want verify that two int arrays are equal, we can use one of these two assertions:

 1import org.junit.Test;
 2
 3import java.util.Arrays;
 4
 5import static org.hamcrest.Matchers.is;
 6import static org.junit.Assert.assertThat;
 7
 8public class ArrayAssertionTest {
 9
10    @Test
11    public void twoIntArraysShouldBeEqual() {
12        int[] actual = new int[]{2, 5, 7};
13        int[] expected = new int[]{2, 5, 7};
14
15        assertThat(actual, is(expected));
16        assertThat(String.format("Expected array: %s but got array: %s",
17                    Arrays.toString(expected),
18                    Arrays.toString(actual)
19                ),
20                actual,
21                is(expected)
22        );
23    }
24}

Asserting Lists

If we want to write an assertion that verifies that the size of a list is correct, we can create the required Hamcrest matcher by invoking the hasSize() method of the Matchers class. For example, if we want to verify that the size of an empty list is 0, we can use one of these two assertions:

 1import org.junit.Test;
 2
 3import java.util.ArrayList;
 4import java.util.List;
 5
 6import static org.hamcrest.Matchers.hasSize;
 7import static org.junit.Assert.assertThat;
 8
 9public class ListAssertionTest {
10
11    @Test
12    public void sizeOfEmptyListShouldBeZero() {
13        List<String> emptyList = new ArrayList<>();
14
15        assertThat(emptyList, hasSize(0));
16        assertThat(String.format("Expected size to be: 0 but was: %d",
17                        emptyList.size()
18                ),
19                emptyList,
20                hasSize(0)
21        );
22    }
23}

If we want to write an assertion that verifies that a list contains the correct objects, one of these two Hamcrest matchers:

  • If we want to verify that the list contains the expected objects in the correct order, we can create the correct Hamcrest matcher by invoking the contains() method of the Matchers class.
  • If we want to verify that the list contains the expected objects in any order, we can create the correct Hamcrest matcher by invoking the containsInAnyOrder() method of the Matchers class.

The test class, which verifies that a list contains the correct objects, looks as follows:

 1import org.junit.Before;
 2import org.junit.Test;
 3
 4import java.util.ArrayList;
 5import java.util.Arrays;
 6import java.util.List;
 7
 8import static org.hamcrest.Matchers.contains;
 9import static org.hamcrest.Matchers.containsInAnyOrder;
10import static org.junit.Assert.assertThat;
11
12public class ListAssertionTest {
13
14    private Object first;
15    private Object second;
16    private List<Object> list;
17
18    @Before
19    public void createAndInitializeList() {
20        first = new Object();
21        second = new Object();
22        list = Arrays.asList(first, second);
23    }
24
25   @Test
26   public void listShouldContainCorrectObjectsInCorrectOrder() {
27       assertThat(list, contains(first, second));
28   }
29
30   @Test
31   public void listShouldContainCorrectObjectsInAnyOrder() {
32       assertThat(list, containsInAnyOrder(first, second));
33   }
34}
Unfortunately the Matchers class has no method that can be used for writing an assertion that verifies that a list does not contain a specific object. If you want do this, you can either create a custom Hamcrest matcher or use the standard JUnit 4 assertions .

Asserting Maps

If we want to verify that a map contains the correct key, we can create the required Hamcrest matcher by invoking the hasKey() method of the Matchers class. The source code of our test method looks as follows:

 1import org.junit.Before;
 2import org.junit.Test;
 3
 4import java.util.HashMap;
 5import java.util.Map;
 6
 7import static org.hamcrest.Matchers.hasKey;
 8import static org.junit.Assert.assertThat;
 9
10public class MapAssertionTest {
11
12    private static final String KEY = "key";
13
14    private Object expected;
15    private Map<String, Object> map;
16
17    @Before
18    public void createAndInitializeMap() {
19        map = new HashMap<>();
20
21        expected = new Object();
22        map.put(KEY, expected);
23    }
24
25    @Test
26    public void shouldContainCorrectKey() {
27        assertThat(map, hasKey(KEY));
28    }
29}

If we want to verify that a map contains the correct entry, we can create the required Hamcrest matcher by invoking the hasEntry() method of the Matchers class. The source code of our test method looks as follows:

 1import org.junit.Before;
 2import org.junit.Test;
 3
 4import java.util.HashMap;
 5import java.util.Map;
 6
 7import static org.hamcrest.Matchers.hasEntry;
 8import static org.junit.Assert.assertThat;
 9
10public class MapAssertionTest {
11
12    private static final String KEY = "key";
13
14    private Object expected;
15    private Map<String, Object> map;
16
17    @Before
18    public void createAndInitializeMap() {
19        map = new HashMap<>();
20
21        expected = new Object();
22        map.put(KEY, expected);
23    }
24
25    @Test
26    public void shouldContainObjectWithCorrectKey() {
27        assertThat(map, hasEntry(KEY, expected));
28    }
29}
Unfortunately the Matchers class has no methods that can be used for writing assertions which verify that a map does not contain a key or does not have an entry. If you want do this, you can either create a custom Hamcrest matcher or use the standard JUnit 4 assertions .

Combining Hamcrest Assertions

This section assumes that you are familiar with the system under test .

If we want to create an assertion that consists of multiple Hamcrest matchers, we can create the required Hamcrest matcher by choosing one of these two options:

  • If we want to write an assertion, which ensures that all conditions are met, we can create the required Hamcrest matcher by invoking the allOf() method of the Matchers class.
  • If we want to write an assertion, which ensures that any condition is met, we can create the required Hamcrest matcher by invoking the anyOf() method of the Matchers class.

After we have created the Hamcrest matcher, we can specify the conditions by using Hamcrest matchers. After we have created our conditions, we have to pass our Hamcrest matchers to the allOf() or anyOf() method as method parameters.

The following examples demonstrate how we can combine multiple Hamcrest matchers when we are writing assertions for a Task object. These examples use the hasProperty() matcher that takes the following method parameters:

  • The name of the property.
  • The Hamcrest matcher that inspects the value of the property.

If we want to verify that all field values of the created Task object are correct, we have to write a test method that looks as follows:

 1import org.junit.Before;
 2import org.junit.Test;
 3
 4import static org.hamcrest.Matchers.allOf;
 5import static org.hamcrest.Matchers.hasProperty;
 6import static org.hamcrest.Matchers.is;
 7import static org.hamcrest.Matchers.nullValue;
 8import static org.junit.Assert.assertThat;
 9
10public class TaskTest {
11
12    private static final Long ID = 1L;
13    private static final Long ASSIGNEE_ID = 99L;
14    private static final Long CREATOR_ID = 44L;
15    private static final String TITLE = "Write an example project";
16    private static final String DESCRIPTION = "description";
17
18	private Task task;
19
20	@Before
21	public void createTask() {
22        task = Task.getBuilder()
23                .withId(ID)
24                .withAssignee(ASSIGNEE_ID)
25                .withCreator(CREATOR_ID)
26                .withTitle(TITLE)
27                .withDescription(DESCRIPTION)
28                .build();
29	}
30
31    @Test
32    public void build_shouldCreateTaskWithCorrectFieldValues() {
33        assertThat(task, allOf(
34                hasProperty("id", is(ID)),
35                hasProperty("assignee", hasProperty("userId",
36						is(ASSIGNEE_ID))
37				),
38                hasProperty("closer", nullValue()),
39                hasProperty("creator", hasProperty("userId",
40						is(CREATOR_ID))
41				),
42                hasProperty("title", is(TITLE)),
43                hasProperty("description", is(DESCRIPTION)),
44                hasProperty("status", is(TaskStatus.OPEN)),
45                hasProperty("resolution", nullValue())
46        ));
47    }
48}

If we want to verify that any field value of the created Task object is correct, we have to write a test method that looks as follows:

 1import org.junit.Before;
 2import org.junit.Test;
 3
 4import static org.hamcrest.Matchers.anyOf;
 5import static org.hamcrest.Matchers.hasProperty;
 6import static org.hamcrest.Matchers.is;
 7import static org.hamcrest.Matchers.nullValue;
 8import static org.junit.Assert.assertThat;
 9
10public class TaskTest {
11
12    private static final Long ID = 1L;
13    private static final Long ASSIGNEE_ID = 99L;
14    private static final Long CREATOR_ID = 44L;
15    private static final String TITLE = "Write an example project";
16    private static final String DESCRIPTION = "description";
17
18	private Task task;
19
20	@Before
21	public void createTask() {
22        task = Task.getBuilder()
23                .withId(ID)
24                .withAssignee(ASSIGNEE_ID)
25                .withCreator(CREATOR_ID)
26                .withTitle(TITLE)
27                .withDescription(DESCRIPTION)
28                .build();
29	}
30
31    @Test
32    public void build_shouldCreateTaskWithAtLeastOneCorrectFieldValue() {
33        assertThat(task, anyOf(
34                hasProperty("id", is(ID)),
35                hasProperty("assignee", hasProperty("userId",
36						is(ASSIGNEE_ID))
37				),
38                hasProperty("closer", nullValue()),
39                hasProperty("creator", hasProperty("userId",
40						is(CREATOR_ID))
41				),
42                hasProperty("title", is(TITLE)),
43                hasProperty("description", is(DESCRIPTION)),
44                hasProperty("status", is(TaskStatus.OPEN)),
45                hasProperty("resolution", nullValue())
46        ));
47    }
48}

We can now write different assertions by using Hamcrest matchers. Let’s find out when we should use this technique.

When Should We Use Hamcrest?

I think that these examples have demonstrated that writing assertions with Hamcrest is a better choice than using the “standard” JUnit 4 assertions because of three reasons:

  • We can pass the actual and expected values in the correct order.
  • Hamcrest matchers make our assertions look like a natural language which make our tests easier to read.
  • The assertThat() method protects its users from themselves. It is not possible to pass the method parameters in the wrong order because if we do so, our tests won’t compile.

In other words, if you want write your assertions with Hamcrest, feel free to do so. I won’t use it myself because I am a big fan of AssertJ that helps me to write assertions by using a fluent API.

However, I use Hamcrest matchers when I am writing tests for my Spring MVC controllers by using the Spring MVC Test framework.

Let’s move on and summarize what we learned from this lesson.

Summary

This lesson has taught us four things:

  • If we want to write assertions with Hamcrest, we have to use the assertThat() method of the org.junit.Assert class.
  • If we want to combine Hamcrest matchers, we can use either the allOf() or anyOf() method of the Matchers class.
  • Writing assertions with Hamcrest is a better choice than using the “standard” JUnit 4 assertions.
  • If we are writing tests by using the Spring MVC Test framework, we can write assertions by using Hamcrest.

Get the source code from Github