Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

In this quick tutorial, we’ll have a look at AssertJ’s exception-dedicated assertions.

2. Without AssertJ

In order to test if an exception was thrown, we’d need to catch the exception and then perform assertions:

try {
    // ...
} catch (Exception e) {
    // assertions
}

But, what if an exception isn’t thrown? In that case, the test would pass; this is why it’s necessary to fail test cases manually.

3. With AssertJ

Using Java 8, we can do assertions on exceptions easily, by leveraging AssertJ and lambda expressions.

3.1. Using assertThatThrownBy()

Let’s check if indexing an out of bounds item in a list raises an IndexOutOfBoundsException:

assertThatThrownBy(() -> {
    List<String> list = Arrays.asList("String one", "String two");
    list.get(2);
}).isInstanceOf(IndexOutOfBoundsException.class)
  .hasMessageContaining("Index: 2, Size: 2");

Notice how the code fragment that might throw an exception gets passed as a lambda expression.

Of course, we can leverage various standard AssertJ assertions here like:

.hasMessage("Index: %s, Size: %s", 2, 2)
.hasMessageStartingWith("Index: 2")
.hasMessageContaining("2")
.hasMessageEndingWith("Size: 2")
.hasMessageMatching("Index: \\d+, Size: \\d+")
.hasCauseInstanceOf(IOException.class)
.hasStackTraceContaining("java.io.IOException");

3.2. Using assertThatExceptionOfType

The idea is similar to the example above, but we can specify the exception type at the beginning:

assertThatExceptionOfType(IndexOutOfBoundsException.class)
  .isThrownBy(() -> {
      // ...
}).hasMessageMatching("Index: \\d+, Size: \\d+");

3.3. Using assertThatIOException and Other Common Types

AssertJ provides wrappers for common exception types like:

assertThatIOException().isThrownBy(() -> {
    // ...
});

And similarly:

  • assertThatIllegalArgumentException()
  • assertThatIllegalStateException()
  • assertThatIOException()
  • assertThatNullPointerException()

3.4. Separating the Exception From the Assertion

An alternative way to write our unit tests is writing the when and then logic in separate sections:

// when
Throwable thrown = catchThrowable(() -> {
    // ...
});

// then
assertThat(thrown)
  .isInstanceOf(ArithmeticException.class)
  .hasMessageContaining("/ by zero");

3.5. Asserting Fields of Custom Exceptions

AssertJ provides several convenient ways to assert custom exception fields. Among these options, we find the catchThrowableOfType() method. As the name indicates, it catches an exception of a specific type.

Before delving deep into the details, let’s consider the CityNotFoundException custom exception:

public class CityNotFoundException extends RuntimeException {

    private String city;
    private String message;

    CityNotFoundException(String city, String message) {
        this.city = city;
        this.message = message;
    }

    // Getters

}

Simply put, this exception will be thrown to signal that a given city doesn’t exist. This is why we choose to define two fields: city and message.

Next, let’s create a new class to hold the logic of searching cities:

public final class CityUtils {

    private static final List<String> CITIES = Arrays.asList("Tamassint", "London", "Madrid", "New york");

    public static String search(String searchedCity) {
        return CITIES.stream()
          .filter(searchedCity::equals)
          .findFirst()
          .orElseThrow(() -> new CityNotFoundException(searchedCity, "The specified city is not found"));
    }

}

Now, let’s add a test case to exemplify how to assert the fields of our custom exception:

@Test
public void whenUsingCatchThrowableOfType_thenAssertField() {
    String givenCity = "Paris";
    CityNotFoundException exception = catchThrowableOfType(() -> CityUtils.search(givenCity), CityNotFoundException.class);

    assertThat(exception.getCity()).isEqualTo(givenCity);
    assertThat(exception.getMessage()).isEqualTo("The specified city is not found");
}

Here, we used catchThrowableOfType() to catch CityNotFoundException. Then, we used assertThat() to check the city and message properties.

Alternatively, we can use assertThatThrownBy() to achieve the same objective:

@Test
public void whenUsingAssertThatThrownBy_thenAssertField() {
    String givenCity = "Geneva";
    assertThatThrownBy(() -> CityUtils.search(givenCity)).isInstanceOf(CityNotFoundException.class)
      .extracting("city")
      .isEqualTo(givenCity);
}

In a nutshell, we used the extracting() method to extract the city property. Then, we chained it with the isEqualTo() method to assert its value.

4. Conclusion

In this short article, we discussed different ways to use AssertJ for performing assertions on exceptions.

As always, the code relating to this article is available over on GitHub.

Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – REST with Spring (eBook) (everywhere)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.