Grouped Assertions in JUnit 5 – assertAll()

HOME

What is JUnit5?

JUnit 5 is composed of several different modules from three different sub-projects.

JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage

The JUnit Platform serves as a foundation for launching testing frameworks on the JVM. It also defines the Test Engine  API for developing a testing framework that runs on the platform.

JUnit Jupiter is the combination of the new programming model and extension model for writing tests and extensions in JUnit 5. The Jupiter sub-project provides a Test Engine for running Jupiter based tests on the platform.

JUnit Vintage provides a Test Engine for running JUnit 3 and JUnit 4 based tests on the platform. It requires JUnit 4.12 or later to be present on the class path or module path.

To use JUnit5, add the Junit5 maven dependency to the POM.xml

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.8.2</version>
    <scope>test</scope>
</dependency>

<dependency>
	<groupId>org.junit.jupiter</groupId>
	<artifactId>junit-jupiter-api</artifactId>
    <version>5.8.2</version>
	<scope>test</scope>
</dependency>

JUnit Jupiter comes with many of the assertion methods that JUnit 4 already has and adds a few more that lend themselves well to being used with Java 8 lambdas. All JUnit Jupiter assertions are static methods. They come from class:

org.junit.jupiter.api.Assertions

JUnit 5 supports an additional Assertion feature called Grouped assertions. In JUnit4, when you have to assert let’s say – 3 different conditions, then you need to write 3 different assertions and they will be executed sequentially. Imagine, 2nd assertion fails, then the program stops there and will not go to the 3rd assertion. To overcome this problem, JUnit5 has a new assertion called Grouped assertion that execute all the conditions present within it using assertAll(), irrespective of the fact if any assertion fails or not and generate a consolidated report with all the failures. To be honest, I love this feature and use very frequently.

Grouped Assertions With Heading As Parameter

Example 1– Below is an example of positive assertAll(). In the below example, all assertions are of same type assertEquals() within assertAll() assertion. It consists of the heading parameter with the value “GroupedAssertionsWithSameAssertionType”.

@Test
void allPositive1() {
   assertAll(
     "GroupedAssertionsWithSameAssertionType",
      () -> assertEquals(8, 5+3, "8 is not sum of 5 and 3"),
      () -> assertEquals("java", "JAVA".toLowerCase()),
      () -> assertEquals(16,4*4,"16 is not product of 4 and 4")
   );
}

Result

As all 3 assertions pass, so the final result passes.

Example2 – In the below example, the assertions are of different types assertEquals(), assertNotNull and assertNotEquals() within assertAll() assertion. It consists of the heading parameter with the value “GroupedAssertionsWithDifferentAssertionType”.

@Test
void allPositive2() {

    String str ="Spring";
    assertAll(
        "GroupedAssertionsWithDifferentAssertionType",
         () -> assertEquals(8, 5+3, "8 is not sum of 5 and 3"),
         () -> assertNotNull(str, () -> "The string should be null"),
         () -> assertEquals("java", "JAVA".toLowerCase()),
         () -> assertNotEquals(20,5*3,"20 is product of 5 and 3")
    );
 }

Result

As all 3 assertions pass, so the final result passes.

Example 3 – In the below example, out of 4 assertions, 3 assertions are failing, so the output will have the detail about all 3 assertion errors.

 @Test
 void allNegative() {

    String str ="Spring";
    Iterable<String> iterat1 = new ArrayList<>(asList("Java", "Junit4", "Test"));
    Iterable<String> iterat2 = new ArrayList<>(asList("Java", "Junit5", "Test"));
    // In a grouped assertion all assertions are executed, and all failures will be reported together
    assertAll(
        "Negative-GroupedAssertionsWithDifferentAssertionType",
        () -> assertIterableEquals(iterat1, iterat2),
        () -> assertNull(str, () -> "The string should be null"),
        () -> assertEquals("java", "JAVA"),
        () -> assertNotEquals(20,5*3,"20 is product of 5 and 3")
     );
 }

Result

As one of the assert in the group fails, instead of AssertionFailureError it results in MultipleFailuresError thereby displaying the heading of the grouped assertion passed as the input parameter i.e. Negative-GroupedAssertionsWithDifferentAssertionType in this example. This image shows all the 3 assertion failures.

Assertion 1 fails as we were expecting JUnit4 , but response has JUnit5
Assertion 2 fails as string was not NULL.
Assertion 3 fails as java is not equal to JAVA (case sensitivity).

Grouped Assertions Without Heading As Parameter

The assertAll () can be implemented without using the heading parameter. The below example is same as the above one, we are just skipping the heading part.

@Test
void allNegative() {

      String str ="Spring";
      Iterable<String> iterat1 = new ArrayList<>(asList("Java", "Junit4", "Test"));
      Iterable<String> iterat2 = new ArrayList<>(asList("Java", "Junit5", "Test"));
      // In a grouped assertion all assertions are executed, and all failures will be reported together
      assertAll(
          () -> assertIterableEquals(iterat1, iterat2),
          () -> assertNull(str, () -> "The string should be null"),
          () -> assertEquals("java", "JAVA"),
          () -> assertNotEquals(20,5*3,"20 is product of 5 and 3")
      );
  }

Result

The result displays without heading.

Nested Or Dependent Grouped Assertions

When one assertAll() includes one or more assertAll() then these are referred to as a Nested or Dependent grouped assertions.

Example 1 – In this case, first the assertAll() validates if sum is correct or not. The sum is correct here, so the control moves to the nested assertAll() to verify all the assertions present within it.

@Test
void allDependentPositive() {

   String str ="Spring";

   // Within a code block, if an assertion fails the subsequent code in the same block will be skipped.
    assertAll(
         "DependentPositiveAssertions",
         () -> {
                assertEquals(8, 5 + 3, "8 is not sum of 5 and 3");

                // Executed only if the previous assertion is valid.
                assertAll("sub-heading",
                   () -> assertNotNull(str, () -> "The string should be null"),
                   () -> assertEquals("java", "JAVA".toLowerCase()),
                   () -> assertEquals(20, 5 * 4, "20 is product of 5 and 4")
                ); // end of inner AssertAll()
           }

      );  // end of outer AssertAll()
 }

Result

All the assertions within nested assertAll() are passes. So the final result passes.

Example 2 – In the below example, outer AssertAll() fails, so all the assertions within nested/dependent assertAll() are not executed.

 @Test
 void allDependentNegative() {

    String str ="Spring";

    // Within a code block, if an assertion fails the subsequent code in the same block will be skipped.
    assertAll(
       "DependentPositiveAssertions",
        () -> {
                assertEquals(8, 5 + 4, "8 is not sum of 5 and 3");

                // Executed only if the previous assertion is valid.
                assertAll("sub-heading",
                   () -> assertNull(str, () -> "The string should be null"),
                   () -> assertNotEquals("java", "JAVA".toLowerCase()),
                   () -> assertNotEquals(20, 5 * 4, "20 is product of 5 and 4")
               ); // end of inner AssertAll()
           }

        ); // end of outer AssertAll()
    }

Result

Example 3 – In the below example, outer AssertAll() passes, so all the assertions within nested/dependent assertAll() are executed.

@Test
void allDependentNegative1() {

    String str ="Spring";

   // Within a code block, if an assertion passes the subsequent code in the same block will be executed.
    assertAll(
      "DependentNegativeAssertions",
      () -> {
             assertEquals(8, 5 + 3, "8 is not sum of 5 and 3");

             // Executed only if the previous assertion is valid.
             assertAll("sub-heading",
               () -> assertNull(str, () -> "The string should be null"),
               () -> assertNotEquals("java", "JAVA".toLowerCase()),
               () -> assertNotEquals(20, 5 * 4, "20 is product of 5 and 4")
             ); // end of inner AssertAll()
         }

      ); // end of outer AssertAll()
    }

Result

The nested assertions have failed. So they can be seen in the execution status.

In short,

  1. When first assertAll() method passes, then all the subsequent assertions within that block will be executed and these assertions can further pass or fails.
  2. When the first assertAll() assertion fails, then the execution of subsequent assertions are skipped.

That’s it! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s