Writing Assertions With AssertJ

After we have finished this lesson, we

  • Can write simple assertions with AssertJ.
  • Understand why we should write our assertions with AssertJ.

Getting the Required Dependencies

Before we can write assertions with AssertJ, we have to get the required dependencies. We can do it by declaring the assertj-core dependency in our build script. We can select the correct version by following these rules:

  • If we use Java 8, we should use the latest version of the 3.X series. At the moment the latest version is 3.4.1.
  • If we don’t use Java 8, we should use the latest version of the 2.X series. At the moment the latest version is 2.4.1.
This lesson assumes that we are using Java 8.

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.assertj</groupId>
3	<artifactId>assertj-core</artifactId>
4	<version>3.4.1</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.assertj:assertj-core:3.4.1'
4    )
5}

After we have added this dependency into our build script, we can start writing assertions with AssertJ.

Writing Assertions With AssertJ

When we want to write assertions with AssertJ, we have to use the assertThat() method of the org.assertj.core.api.Assertions class. This method takes the actual value or object as a method parameter and selects the returned object by using the type of the method parameter. After we have invoked the assertThat() method, we can write our assertions by using the returned object.

Because AssertJ provides a fluent API, each assertion method returns a reference to the “assertion object”. This means that we can chain assertions by simply invoking another assertion method.

For example, if we want to write an assertion, which verifies that the size of the asserted list is correct and that the list contains the correct objects in the correct order, we can write our assertion by using the following code:

 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.assertj.core.api.Assertions.assertThat;
 9
10public class ListAssertionTest {
11
12    private static final int EXPECTED_SIZE = 2;
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 SizeOfListShouldBeTwoAndItShouldContainCorrectObjects() {
27        assertThat(list)
28                .hasSize(EXPECTED_SIZE)
29                .containsExactly(first, second);
30    }
31}

If we want to provide a custom error message that is shown when our assertion fails, we can use one of these two options:

  • If we want to override the description part of the error message, we have to invoke either the as() or the describeAs() method of the AbstractAssert class.
  • If we want to override the entire error message, we have to invoke the overridingErrorMessage() method of the AbstractAssert class.

The source code of the test class, which demonstrates the usage of these options, looks as follows:

 1import org.junit.Test;
 2
 3import static org.assertj.core.api.Assertions.assertThat;
 4
 5public class BooleanAssertionTest {
 6
 7    private static final boolean TRUE = true;
 8
 9    @Test
10    public void booleanShouldBeTrue() {
11        assertThat(TRUE)
12                .describedAs("Expected boolean to be true but was false")
13                .isTrue();
14    }
15
16    @Test
17    public void booleanShouldBeTrue() {
18        assertThat(TRUE)
19                .overridingErrorMessage(
20						"Expected boolean to be true but was false"
21				)
22                .isTrue();
23    }
24}

The difference of these options is demonstrated in the following:

If our assertion that invokes the describeAs() method fails, we see the following error message:

1org.junit.ComparisonFailure: [Expected boolean to be true but was false]
2Expected :false
3Actual   :true

If our assertion that invokes the overridingErrorMessage() method fails, we see the following error message:

1java.lang.AssertionError: Expected boolean to be true but was false
If I want to provide a custom error message, I use the overridingErrorMessage() method because I want to customize the entire error message. However, if you want to use the describeAs() method, feel free to do so.

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

Asserting Boolean Values

If we want to verify that a boolean value is true, we have to write our assertion by invoking the isTrue() method of the AbstractBooleanAssert class. The source code of our test method looks as follows:

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

If we want to verify that a boolean value is false, we have to write our assertion by invoking the isFalse() method of the AbstractBooleanAssert class. The source code of our test method looks as follows:

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

Asserting That an Object Is Null or Is Not Null

If we want to verify that an object is null, we have to write our assertion by invoking the isNull() method of the AbstractAssert class. The source code of our test method looks as follows:

 1import org.junit.Test;
 2
 3import static org.assertj.core.api.Assertions.assertThat;
 4
 5public class ObjectAssertionTest {
 6
 7    @Test
 8    public void objectShouldBeNull() {
 9        Object actual = null;
10
11        assertThat(actual)
12                .overridingErrorMessage(
13						"Expected object to be null but was: %s",
14                        actual
15                )
16                .isNull();
17    }
18}

If we want to verify that an object is not null, we have to write our assertion by invoking the isNotNull() method of the AbstractAssert class. The source code of our test method looks as follows:

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

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 have to write our assertion by invoking either the isEqualTo() method of the AbstractAssert class or the isEqualByComparingTo() method of the AbstractComparableAssert class. The difference of these methods is:

  • The isEqualTo() method invokes the equals() method.
  • The isEqualByComparingTo() method invokes the compareTo() method of the Comparable interface.

If we want to write an assertion which ensures that two integers are equal, the source code of our test method looks as follows:

 1import org.junit.Test;
 2
 3import static org.assertj.core.api.Assertions.assertThat;
 4
 5public class ObjectAssertionTest {
 6
 7    @Test
 8    public void twoIntegersShouldBeEqual() {
 9        Integer actual = 9;
10        Integer expected = 9;
11
12        assertThat(actual)
13                .overridingErrorMessage(
14						"Expected integer to be: %d but was: %d",
15                        expected,
16                        actual
17                )
18                .isEqualByComparingTo(expected);
19    }
20}

If we want to verify that the expected value (or object) is not equal to the actual value (or object), we have to write our assertion by invoking either the isNotEqualTo() method of the AbstractAssert class or the isNotEqualByComparingTo() method of the AbstractComparableAssert class. These methods are implemented in the same way as the isEqualTo() and isEqualByComparingTo() methods.

If we want to write an assertion which ensures that two integers are not equal, the source code of our test method looks as follows:

 1import org.junit.Test;
 2
 3import static org.assertj.core.api.Assertions.assertThat;
 4
 5public class ObjectAssertionTest {
 6
 7    @Test
 8    public void twoIntegersShouldNotBeEqual() {
 9        Integer actual = 9;
10        Integer expected = 41;
11
12        assertThat(actual)
13                .overridingErrorMessage(
14						"Expected integer to not be: %d but was %d",
15                        expected,
16                        actual
17                )
18                .isNotEqualByComparingTo(expected);
19    }
20}

Asserting Object References

If we want to ensure that two objects refer to the same object, we have to write our assertion by invoking the isSameAs() method of the AbstractAssert class. The source code of our test method looks as follows:

 1import org.junit.Test;
 2
 3import static org.assertj.core.api.Assertions.assertThat;
 4
 5public class ObjectAssertionTest {
 6
 7    @Test
 8    public void shouldPointToSameObject() {
 9        Object actual = new Object();
10        Object expected = actual;
11
12        assertThat(actual)
13                .overridingErrorMessage(
14						"Expected two objects to be same but they were not"
15				)
16                .isSameAs(expected);
17    }
18}

If we want to ensure that two objects don’t refer to the same object, we have to write our assertion by invoking the isNotSameAs() method of the AbstractAssert class. The source code of our test method looks as follows:

 1import org.junit.Test;
 2
 3import static org.assertj.core.api.Assertions.assertThat;
 4
 5public class ObjectAssertionTest {
 6
 7    @Test
 8    public void shouldNotPointToSameObject() {
 9        Object actual = new Object();
10        Object expected = new Object();
11
12        assertThat(actual)
13                .overridingErrorMessage(
14						"Expected to objects to not be same but they were"
15				)
16                .isNotSameAs(expected);
17    }
18}

Asserting the Equality of Two Arrays

If we want to verify that two arrays are equal, we have to write our assertion by invoking the isEqualTo() method of the AbstractArrayAssert class. The source code of our test method looks as follows:

 1import org.junit.Test;
 2import java.util.Arrays;
 3
 4import static org.assertj.core.api.Assertions.assertThat;
 5
 6public class ArrayAssertionTest {
 7
 8    @Test
 9    public void twoIntArraysShouldBeEqual() {
10        int[] actual = new int[]{2, 5, 7};
11        int[] expected = new int[]{2, 5, 7};
12
13        assertThat(actual)
14                .overridingErrorMessage(
15						"Expected array: %s but got array: %s",
16                        Arrays.toString(expected),
17                        Arrays.toString(actual)
18                )
19                .isEqualTo(expected);
20    }
21}

If we want to verify that two arrays are not equal, we have to write our assertion by invoking the isNotEqualTo() method of the AbstractArrayAssert class. The source code of our test method looks as follows:

 1import org.junit.Test;
 2import java.util.Arrays;
 3
 4import static org.assertj.core.api.Assertions.assertThat;
 5
 6public class ArrayAssertionTest {
 7
 8    @Test
 9    public void twoIntArraysShouldNotBeEqual() {
10        int[] actual = new int[]{2, 5, 7};
11        int[] expected = new int[]{2, 5, 71};
12
13        assertThat(actual)
14                .overridingErrorMessage(
15						"Expected array: %s to not be equal to array: %s",
16                        Arrays.toString(expected),
17                        Arrays.toString(actual)
18                )
19                .isNotEqualTo(expected);
20    }
21}

Additional Reading:

Asserting Lists

If we want to write an assertion that verifies that the size of a list is correct, we can use one of these two options:

  • If we want to verify that a list is empty, we can write our assertion by invoking the isEmpty() method of the AbstractIterableAssert class.
  • If we want to verify that the size of the list is correct, we can write our assertion by invoking the hasSize() method of the AbstractIterableAssert class.

For example, if we want to verify that an empty list is empty and the size of a non-empty list is correct, the source code of our test class 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.assertj.core.api.Assertions.assertThat;
 9
10public class ListAssertionTest {
11
12    private static final int EXPECTED_SIZE = 2;
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 sizeOfEmptyListShouldBeZero() {
27        List<String> emptyList = new ArrayList<>();
28
29        assertThat(emptyList)
30                .overridingErrorMessage(
31						"Expected size of empty list to be: 0 but was: %d",
32                        emptyList.size()
33                )
34                .isEmpty();
35    }
36
37    @Test
38    public void sizeOfListShouldBeTwo() {
39        assertThat(list)
40                .overridingErrorMessage(
41						"Expected size of list to be: %d but was: %d",
42                        EXPECTED_SIZE,
43                        list.size()
44                )
45                .hasSize(EXPECTED_SIZE);
46    }
47}

If we want to ensure that a list either contains or does not contain specific objects, we can use these options:

  • If we want to verify that the asserted list contains only the specified objects in the correct order, we have to write our assertion by using the containsExactly() method of the AbstractIterableAssert class.
  • If we want to verify that the asserted list contains only the specified objects in any order, we have to to write our assertion by using the containsExactlyInAnyOrder() method of the AbstractIterableAssert class.
  • If we want to ensure that the asserted list doesn’t contain an object, we have to write our assertion by invoking the doesNotContain() method of the AbstractIterableAssert class.

The source code of our test class, which demonstrates the usage of these assertions, 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.assertj.core.api.Assertions.assertThat;
 9
10public class ListAssertionTest {
11
12    private static final int EXPECTED_SIZE = 2;
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).containsExactly(first, second);
28    }
29
30    @Test
31    public void listShouldContainCorrectObjectsInAnyOrder() {
32        assertThat(list).containsExactlyInAnyOrder(second, first);
33    }
34
35    @Test
36    public void listShouldNotContainIncorrectObjects() {
37        Object incorrect = new Object();
38        assertThat(list).doesNotContain(incorrect);
39    }
40}

Asserting Maps

If we want to verify that a map contains the correct key or that it doesn’t contain an incorrect key, we can write our assertion by using these options:

  • If we want to verify that the asserted map contains the correct key, we have to write our assertion by invoking the containsKey() method of the AbstractMapAssert class.
  • If we want to verify that the asserted map doesn’t contain the incorrect key, we have to write our assertion by invoking the doesNotContainKey() method of the AbstractMapAssert class.

The source code of our test class, which demonstrates the usage of these assertions, looks as follows:

 1import org.junit.Before;
 2import org.junit.Test;
 3
 4import java.util.HashMap;
 5import java.util.Map;
 6
 7import static org.assertj.core.api.Assertions.assertThat;
 8
 9public class MapAssertionTest {
10
11    private static final String INCORRECT_KEY = "incorrectKey";
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).containsKey(KEY);
28    }
29
30    @Test
31    public void shouldNotContainIncorrectKey() {
32        assertThat(map).doesNotContainKey(INCORRECT_KEY);
33    }
34}

If we want to verify that a map contains the correct entry or that it doesn’t contain an entry, we can write our assertions by using the options:

  • If we want to ensure that the asserted map contains the correct entry, we have to write our assertion by invoking the containsEntry() method of the AbstractMapAssert class.
  • If we we want to verify that the asserted map doesn’t have an entry with incorrect key, we have to write our assertion by invoking the doesNotContainEntry() method of the AbstractMapAssert class.

The source code of our test class, which demonstrates the usage of these assertions, looks as follows:

 1import org.junit.Before;
 2import org.junit.Test;
 3
 4import java.util.HashMap;
 5import java.util.Map;
 6
 7import static org.assertj.core.api.Assertions.assertThat;
 8
 9public class MapAssertionTest {
10
11    private static final String INCORRECT_KEY = "incorrectKey";
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).containsEntry(KEY, expected);
28    }
29
30    @Test
31    public void shouldNotContainObjectWithIncorrectKey() {
32        assertThat(map).doesNotContainEntry(INCORRECT_KEY, expected);
33    }
34}

We can now write basic assertions with AssertJ. Let’s move on and find out why we should use AssertJ instead of the “standard” JUnit assertions or Hamcrest.

Why Should We Use AssertJ?

I think that we should write our assertions with AssertJ because of three reasons:

  • Assertions that use AssertJ are faster to write than assertions that use JUnit or Hamcrest because we don’t have to remember to pass the method parameters in the correct order and we don’t have to remember which Hamcrest matcher we should use.
  • AssertJ protects its users from programming errors. Because the assertThat() method of the org.assertj.core.api.Assertions class takes only one method parameter and it returns the assertion object that we can use for writing assertions, it is nearly impossible to make a programming error. For example, we cannot pass its method parameters in the wrong order.
  • AssertJ helps us to write assertions that make sense. I want to use an assertion API that is described by this sentence: “When we invoke the method X, the value Y is returned”. Although I think that the Hamcrest API fulfills this requirement, I think that the AssertJ API is a bit better because it allows me to write assertions that look like natural language.

Let’s compare our options. The following test class contains three test methods which ensure that two integers are equal. The source code of the test class looks as follows:

 1public class ObjectAssertionTest {
 2
 3 	//JUnit
 4    @Test
 5    public void twoIntegersShouldBeEqual() {
 6        Integer actual = 9;
 7        Integer expected = 9;
 8
 9        assertEquals(expected, actual);
10    }
11
12	//Hamcrest
13    @Test
14    public void twoIntegersShouldBeEqual() {
15        Integer actual = 9;
16        Integer expected = 9;
17
18        assertThat(actual, is(expected));
19    }
20
21	//AssertJ
22    @Test
23    public void twoIntegersShouldBeEqual() {
24        Integer actual = 9;
25        Integer expected = 9;
26
27        assertThat(actual).isEqualByComparingTo(expected);
28    }
29}

We should notice that assertions, which use Hamcrest or AssertJ, are a lot easier to read and write than the “standard” JUnit 4 assertion. I must admit that the race between Hamcrest and AssertJ is a tough one, but I think that even this simple example demonstrates that AssertJ is a better choice. The crucial difference is that AssertJ provides a fluent API that is a bit more pleasant to use than the Hamcrest API.

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

Summary

This lesson has taught us three things:

  • The “correct” AssertJ version depends from our Java version.
  • We can write assertions with AssertJ by using the assertThat() method of the org.assertj.core.api.Assertions class.
  • We should use AssertJ because the assertions that use it are easy to read and write.

Get the source code from Github