assertAll in JUnit 5

Using the assertAll method vs asserting in separate statements

Chaanakya
Javarevisited
3 min readJan 18, 2023

--

assertAll method is used to validate all the assertions passed to it.

Here’s what the official documentation says about the method:

Asserts that all supplied executables do not throw exceptions.

If any supplied Executable throws an exception (i.e., a Throwable or any subclass thereof), all remaining executables will still be executed, and all exceptions will be aggregated and reported in a MultipleFailuresError. However, if an executable throws a blacklisted exception — for example, an OutOfMemoryError — execution will halt immediately, and the blacklisted exception will be rethrown as is but masked as an unchecked exception.

The supplied heading will be included in the message string for the MultipleFailuresError.

Usage

@Test
void testAssertions() {
assertAll(
() -> assertEquals("1", "1"),
() -> assertTrue(1 == 2),
......
);
}

Using assertAll vs asserting separately

The difference between passing assertions to this method vs asserting them in separate statements is that “the assertAll method executes all the assertions passed to it, even though some assertion fails”

// Example of assertAll
@Test
void testAssertions() {
assertAll(
() -> assertEquals("1", "1"),
() -> assertEquals("1", "2"),
() -> assertTrue(1 == 2)
);
}


/*
Output:

org.opentest4j.MultipleFailuresError: Multiple Failures (2 failures)
org.opentest4j.AssertionFailedError: expected: <1> but was: <2>
org.opentest4j.AssertionFailedError: expected: <true> but was: <false>
*/

If we write the assertions in separate statements, then the test execution will end immediately whenever an assertion fails. The assertions that follow the failed assertion will not be executed.

// Example of asserting separately
@Test
void testAssertions() {
assertEquals("1", "1");

/*
when the test fails here it throws an AssertionFailedError
and the test fails.
The below assertTrue will not be executed
*/
assertEquals("1", "2");
assertTrue(1 == 2);
}

/*
Output:
org.opentest4j.AssertionFailedError:
Expected :1
Actual :2
*/

So executing all assertions even in case of an assertion failure is an advantage that the assertAll method offers.

Working

Let’s check the code of the assertAll method to see how it works as mentioned.

// code from JUnit 5

static void assertAll(String heading, Stream<Executable> executables) {
Preconditions.notNull(executables, "executables stream must not be null");

List<Throwable> failures = executables //
.peek(executable -> Preconditions.notNull(executable, "individual executables must not be null"))//
.map(executable -> {
try {
executable.execute();
return null;
}
catch (Throwable t) {
BlacklistedExceptions.rethrowIfBlacklisted(t);
return t;
}
}) //
.filter(Objects::nonNull) //
.collect(Collectors.toList());

if (!failures.isEmpty()) {
MultipleFailuresError multipleFailuresError = new MultipleFailuresError(heading, failures);
failures.forEach(multipleFailuresError::addSuppressed);
throw multipleFailuresError;
}
}

Each Executable object/assertion is executed within a try-catch to make sure that the assertion failure is not immediately thrown. The mapper/transformation function returns null if the test passes, and returns throwable if the test fails.

The stream of Executable’s is converted into a stream of Throwable’s. The non-null objects are filtered (the assertions that failed), and are collected into a list. The list is wrapped in a MultipleFailuresError and is thrown at the end collectively.

That’s all for now. Feel free to ask any questions or share any comments you have about the article. See you in the next article.

Happy Coding!

--

--