Writing Assertions With JUnit 5 Assertion API

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 by using the JUnit 5 assertion API. After we have finished this blog post, we:

  • Can write basic assertions with JUnit 5.
  • Know how we can customize the error message shown when an assertion fails.
  • Understand how we can run multiple assertions as an assertion group.

Let's begin.

Writing Assertions With JUnit 5

If we want to write assertions by using the "standard" JUnit 5 API, we must use the org.junit.jupiter.api.Assertions class. It provides static methods which allow us to ensure that the specified condition is true after the system under test has been run.

Before we will take a closer look at these methods, we have to know a few basic rules:

  • If we want to specify a custom error message that's shown when our assertion fails, we have to pass this message as the last method parameter of the invoked assertion method.
  • If we want to compare two values (or objects), we have to pass these values (or objects) to the invoked assertion method in this order: the expected value (or object) and the actual value (or object).

Next, we will find out how we can write assertions with the Assertions class. 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 use the assertTrue() method of the Assertions 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.junit.jupiter.api.Assertions.assertTrue;

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

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

        @Test
        @DisplayName("Should be true")
        void shouldBeTrue() {
            assertTrue(true);
        }
    }
}

If we want to verify that a boolean value is false, we have to use the assertFalse() method of the Assertions 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.junit.jupiter.api.Assertions.assertFalse;

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

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

        @Test
        @DisplayName("Should be false")
        void shouldBeFalse() {
            assertFalse(false);
        }
    }
}

Next, we will 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 use the assertNull() method of the Assertions class. In other 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.junit.jupiter.api.Assertions.assertNull;

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

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

        @Test
        @DisplayName("Should be null")
        void shouldBeNull() {
            assertNull(null);
        }
    }
}

If we want to verify that an object isn't null, we have to use the assertNotNull() method of the Assertions class. In other 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.junit.jupiter.api.Assertions.assertNotNull;

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

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

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

Let's move on and 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 use the assertEquals() method of the Assertions 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.junit.jupiter.api.Assertions.assertEquals;

@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() {
                assertEquals(EXPECTED, ACTUAL);
            }
        }
    }
}

If we want to verify that the expected value (or object) isn't equal to the actual value (or object), we have to use the assertNotEquals() method of the Assertions 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.junit.jupiter.api.Assertions.assertNotEquals;

@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() {
                assertNotEquals(EXPECTED, ACTUAL);
            }
        }
    }
}

Next, we will 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 use the assertSame() method of the Assertions class. In other 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.junit.jupiter.api.Assertions.assertSame;

@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() {
            assertSame(EXPECTED, ACTUAL);
        }
    }
}

If we want to ensure that two objects don't refer to the same object, we have to use the assertNotSame() method of the Assertions class. In other 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.junit.jupiter.api.Assertions.assertNotSame;

@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() {
            assertNotSame(EXPECTED, ACTUAL);
        }
    }
}

Let's move on and 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 use the assertArrayEquals() method of the Assertions 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.junit.jupiter.api.Assertions.assertArrayEquals;

@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() {
            assertArrayEquals(EXPECTED, ACTUAL);
        }
    }
}
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.

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

Asserting That Two Iterables Are Equal

If we want to verify that two iterables are deeply equal, we have to use the assertIterableEquals() method of the Assertions 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.junit.jupiter.api.Assertions.assertIterableEquals;

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

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

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

        @Test
        @DisplayName("Should contain the same elements")
        void shouldContainSameElements() {
            assertIterableEquals(FIRST, SECOND);
        }
    }
}
Two iterables are considered as equal if:

  • They are both null or empty.
  • Both iterables contain the "same" objects or values. To be more specific, JUnit 5 iterates both iterables 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 the exception thrown by the system under test.

Writing Assertions for Exceptions

If we want to write assertions for the exceptions thrown by the system under test, we have to use the assertThrows() method of the Assertions class. This method takes the following method parameters:

  • A Class object that specifies the type of the expected exception.
  • An Executable object that invokes the system under test.
  • An optional error message.

For example, if we want to verify that the system under test throws a NullPointerException, our assertion looks as follows:

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

import static org.junit.jupiter.api.Assertions.assertThrows;

@DisplayName("Writing assertions for exceptions")
class ExceptionAssertionTest {

    @Test
    @DisplayName("Should throw the correct exception")
    void shouldThrowCorrectException() {
        assertThrows(
                NullPointerException.class,
                () -> { throw new NullPointerException(); }
        );
    }
}

Because the assertThrows() method returns the thrown exception object, we can also write additional assertions for the thrown exception. For example, if we want to verify that the thrown exception has the correct message, we can use the following assertions:

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

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

@DisplayName("Writing assertions for exceptions")
class ExceptionAssertionTest {

    @Test
    @DisplayName("Should throw an exception that has the correct message")
    void shouldThrowAnExceptionWithCorrectMessage() {
        final NullPointerException thrown = assertThrows(
                NullPointerException.class,
                () -> { throw new NullPointerException("Hello World!"); }
        );
        assertEquals("Hello World!", thrown.getMessage());
    }
}

On the other hand, even though a test method fails if the system under test throws an exception, sometimes we want to explicitly assert that no exception is thrown by the tested code. If this is the case, we have to use the assertDoesNotThrow() method of the Assertions class. When we want to verify that no exception is thrown by the system under test, we can use one of these two options:

First, if we don't want to write assertions for the value returned by the system under test, we have to pass the following method parameters to the assertDoesNotThrow() method:

  • An Executable object that invokes the system under test.
  • An optional error message.

For example, if we want to verify that the system under test doesn't throw an exception, our assertion looks as follows:

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

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;

@DisplayName("Writing assertions for exceptions")
class ExceptionAssertionTest {

    @Test
    @DisplayName("Should not throw an exception")
    void shouldNotThrowException() {
        assertDoesNotThrow(() -> {});
    }
}

Second, if we want to write assertions for the value returned by the system under test, we have to pass the following method parameters to the assertDoesNotThrow() method:

  • A ThrowingSupplier object that invokes the system under test (and returns the return value).
  • An optional error message.

For example, if we want to verify that the system under test doesn't throw an exception AND we want to verify that the system under test returns the correct message, our assertion looks as follows:

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

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;

@DisplayName("Writing assertions for exceptions")
class ExceptionAssertionTest {

    @Test
    @DisplayName("Should not throw an exception")
    void shouldNotThrowException() {
        String message = assertDoesNotThrow(() -> { return "Hello World!"; } );
        assertEquals("Hello World!", message);
    }
}

Next, we will find out how we can write assertions for the execution time of the system under test.

Writing Assertions for the Execution Time of the System Under Test

If we want to ensure that the execution of the system under test is completed before the specified timeout is exceeded, we can use the assertTimeout() and assertTimeoutPreemptively() methods of the Assertions class. Both of these methods take the following method parameters:

  • A Duration object that specifies the timeout.
  • An Executable or a ThrowingSupplier object that invokes the system under test.
  • An optional error message that is shown if the specified timeout is exceeded.

Even though these two methods are quite similar, they have one crucial difference. This difference is explained in the following:

  • If we use the assertTimeout() method, the provided Executable or ThrowingSupplier will be executed in the same thread as the code that calls it. Also, this method doesn't abort the execution if the timeout is exceeded.
  • If we use the assertTimeoutPreemptively() method, the provided Executable or ThrowingSupplier will be executed in a different thread than the code that calls it. Also, this method aborts the execution if the timeout is exceeded.

As we see, we can verify that the execution of the system under test is completed before the specified timeout is exceeded by using one of these two options:

First, if we want that the execution isn't aborted if the timeout is exceeded, we have to use the assertTimeout() method of the Assertions class. For example, if we want to verify that the system under test returns the message: 'Hello world!' before the specified timeout (50ms) is exceeded, we have to write assertions that look as follows:

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

import java.time.Duration;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTimeout;

@DisplayName("Writing assertions for the execution time of the system under test")
class TimeoutAssertionTest {

    @Test
    @DisplayName("Should return the correct message before timeout is exceeded")
    void shouldReturnCorrectMessageBeforeTimeoutIsExceeded() {
        final String message = assertTimeout(Duration.ofMillis(50), () -> {
            Thread.sleep(20);
            return "Hello World!";
        });
        assertEquals("Hello World!", message);
    }
}

Second, if we want that the execution is aborted if the timeout is exceeded, we have to use the assertTimeoutPreemptively() method of the Assertions class. For example, if we want to verify that the system under test returns the message: 'Hello world!' before the specified timeout (50ms) is exceeded, we have to write assertions that look as follows:

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

import java.time.Duration;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;

@DisplayName("Writing assertions for the execution time of the system under test")
class TimeoutAssertionTest {

    @Test
    @DisplayName("Should return the correct message before timeout is exceeded")
    void shouldReturnCorrectMessageBeforeTimeoutIsExceeded() {
        final String message = assertTimeoutPreemptively(Duration.ofMillis(50), () -> {
            Thread.sleep(20);
            return "Hello World!";
        });
        assertEquals("Hello World!", message);
    }
}

We can now write basic assertions with JUnit 5. Let's move on and find out how we can customize the error messages which are shown by JUnit 5 if an assertion fails.

Providing a Custom Error Message

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

First, we can create a new String object and pass this object as the last method parameter of the invoked assertion assertion method. This is a good choice if our error message has no parameters. For example, if we want to provide a custom error message for an assertion which verifies that a boolean value is false, we have to write an assertion that looks as follows:

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

import static org.junit.jupiter.api.Assertions.assertFalse;

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

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

        @Test
        @DisplayName("Should be false")
        void shouldBeFalse() {
            assertFalse(false, "The boolean is not false");
        }
    }
}

Second, we can create a message supplier (Supplier) and pass this supplier as the last method parameter of the invoked assertion method. If we use this approach, JUnit 5 creates the actual error messages only if our assertion fails. That's why this is a good choice if we want to create a "complex" error message that has parameters.

For example, if we want to provide a custom error message for an assertion which verifies that a map contains the given key, we have to write an assertion that looks as follows:

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

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

import static org.junit.jupiter.api.Assertions.assertTrue;

@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);
    }

    @Test
    @DisplayName("Should contain the correct key")
    void shouldContainCorrectKey() {
        assertTrue(
                map.containsKey(KEY), 
                () -> String.format("The map doesn't contain the key: %s", KEY)
        );
    }
}
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 is prepended to the default error message of the used assertion object. At first, this feels a bit weird, but it's actually quite useful after you get used to it.

Next, we will find out how we can group assertions with JUnit 5.

Grouping Assertions

If we have to write an assertion for a state that requires multiple assertions, we can group our assertions by using the assertAll() method of the Assertions class. This method takes the following method parameters:

  • An optional heading that identifies the asserted state.
  • An array, a Collection, or a Stream of Executable objects which invoke our assertions.

When we invoke the assertAll() method, it invokes all specified assertions and reports all assertion failures after all assertions have been run.

Let's assume that we have to write an assertion which verifies that a Person object has the correct name. 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 verify that the asserted Person object has the correct first and last name. In other words, we have to write an assertion that looks as follows:

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

import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertEquals;

@DisplayName("Group multiple assertions")
class GroupAssertionsTest {

    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() {
        assertAll("name",
                () -> assertEquals(FIRST_NAME, 
                        person.getFirstName(), 
                        "The first name is incorrect"
                ),
                () -> assertEquals(LAST_NAME, 
                        person.getLastName(), 
                        "The last name is incorrect"
                )
        );
    }
}

We can now write basic assertions with JUnit 5, provide a custom error message that is shown when an assertion fail, and group assertions with JUnit 5.

If you want to get access to up-to-date material which is essentially a better version of my JUnit 5 tutorial, you should take a look at my Introduction to JUnit 5 course.

Additional Reading:

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

Summary

This blog post has taught us four things:

  • If we want to write assertions by using the "standard" JUnit 5 API, we must use the org.junit.jupiter.api.Assertions class.
  • If we want to specify a custom error message that has no parameters, we have to create a new String object and pass this object as the last method parameter of the invoked assertion method.
  • If we want to specify a "complex" error message that has parameters, we have to create a message supplier (Supplier) and pass this supplier as the last method parameter of the invoked assertion method.
  • If we have to write an assertion for a state that requires multiple assertions, we can group our assertions by using the assertAll() method of the Assertions class.

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

8 comments… add one
  • Arbind Apr 17, 2018 @ 19:03

    Hello,
    Thanks for this nice article. It really help me understand assertions.

    I have one query,
    In case of failed group assertion, is it possible to execute next statement

    ...
    ...
    assertAll("test_Date Assertion",
    () -> assertEquals(CommUtils.getXpathField(xmlSoapResponse, "responseCode"),"01"),
    () -> assertTrue(this.assertionUtility.isValidSOAPResponse(xmlSoapResponse)),
    () -> assertEquals(datesFromDB.getCurrentProcessingDate().toString(), processFromService));
    log.debug("Second Set");
    ......
    .....

    Thanks

    • Ardalan Dec 4, 2018 @ 15:40

      Try to use a Thread between every statement or make loop

  • Ardalan Dec 4, 2018 @ 15:40

    nice Article Prefect,Merci

  • Asafir Jan 8, 2019 @ 10:18

    While trying to use assertTimeout and assertThrow in Groovy a RunTimeException is thrown:
    Ambiguous method overloading for method org.junit.jupiter.api.Assertions#assertTimeout
    Cannot resolve which method to invoke for [class java.time.Duration]
    [class java.time.Duration, interface org.junit.jupiter.api.function.ThrowingSupplier]
    [class java.time.Duration, interface org.junit.jupiter.api.function.Executable]

    Any idea how to solve this?
    Many thanks!

  • A Jackson Oct 8, 2020 @ 16:00

    Great and informative post.
    Question is, how to use jUnit 5 with modules. We are in the 2020, and we should use modules, so it would be great if you could tell how to use it with jar in MODULEPATH instead of CLASSPATH.
    And what need to be added in module-info.java to be able to compile it and run it.

    • Petri Oct 8, 2020 @ 21:11

      I have to confess that I cannot answer to your question because I have never used Java 9 modules. However, I found one blog post that might answer to your question.

Leave a Reply