Igor's Techno Club

Java AssertJ Features I Wish I Knew Earlier

asserj-new-features

Previously I already covered most underrated features of Java JUnit 5, today I would like to show you few underrated AssertJ features which I personally found quite useful.

For those who are new to AssertJ, AssertJ is a powerful Java library that provides a rich set of assertions for more expressive and readable tests. As developers, we often discover features that could have significantly improved our testing practices if we had known about them earlier. In this article, we'll explore several AssertJ assertions and techniques that can enhance your testing experience and code quality.

Extracting and Filtering

Available since AssertJ 2.5.0

The extracting() and filteredOn() methods are powerful tools for performing assertions on specific properties of objects or filtering collections before making assertions. These methods can greatly simplify your test code and make it more readable.

Example:

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;

List<Person> people = Arrays.asList(
    new Person("John", 25),
    new Person("Jane", 30),
    new Person("Bob", 35)
);

assertThat(people)
   .extracting("name", "age")
   .containsExactly(
        tuple("John", 25),
        tuple("Jane", 30)
    );


assertThat(people)
    .filteredOn(person -> person.getAge() > 30)
    .hasSize(1)
    .extracting("name")
    .containsOnly("Bob");

In this example, we use extracting() to assert on specific properties of the Person objects in the list. The filteredOn() method allows us to apply a predicate to filter the list before making assertions.

Soft Assertions

Available since AssertJ 2.0.0

Soft assertions allow you to collect multiple assertion failures and report them together, rather than stopping at the first failure. This can be particularly useful when you want to check multiple conditions and get a comprehensive report of all failures.

Example:

import org.assertj.core.api.SoftAssertions;
import org.assertj.core.api.AutoCloseableSoftAssertions;

@Test
void softAssertionsExample() {
    try (AutoCloseableSoftAssertions softly = new AutoCloseableSoftAssertions()) {
        softly.assertThat(1 + 1).isEqualTo(3);
        softly.assertThat("hello").startsWith("a");
        softly.assertThat(Arrays.asList(1, 2, 3)).contains(4);
    } // assertAll() is called automatically
}

Using AutoCloseableSoftAssertions with a try-with-resources block ensures that assertAll() is called automatically, making your tests more concise and less prone to errors.


Like the article? Subscribing to the blog



Describing Assertions

Available since AssertJ 1.0.0

The as() method allows you to provide custom descriptions for your assertions, making test failure messages more informative and easier to understand.

Example:

String result = "Hello, World!";
assertThat(result)
   .as("Greeting message")
   .isEqualTo("Hello, World!")
   .startsWith("Hello")
   .endsWith("!");

If any of these assertions fail, the error message will include the custom description "Greeting message", making it easier to identify the context of the failure.

usingFieldByFieldElementComparator for Complex Object Comparisons in Collections

Available since AssertJ 2.0.0

When comparing lists or collections of complex objects, the usingFieldByFieldElementComparator provides an elegant solution for field-by-field comparisons without the need for custom comparators.

Example:

import static org.assertj.core.api.Assertions.assertThat;

List<Person> actualPersons = List.of(
        new Person("John", 30),
        new Person("Jane", 25)
);

List<Person> expectedPersons = List.of(
        new Person("John", 30),
        new Person("Jane", 25)
);

assertThat(actualPersons)
       .usingFieldByFieldElementComparator()
       .containsExactlyInAnyOrderElementsOf(expectedPersons);

This approach is particularly useful when dealing with objects that lack proper equals/hashCode implementations or when you want to compare specific fields without relying on the object's equality method.

usingRecursiveComparison for Deep Object Graph Assertions

Available since AssertJ 3.14.0

For scenarios where you need to compare two complex objects with nested fields, usingRecursiveComparison provides a powerful solution. It allows for a deep, recursive comparison of object graphs, accounting for nested fields without the need for writing deep assertion chains.

Example:

import static org.assertj.core.api.Assertions.assertThat;

Person person1 = new Person("John", 30, new Address("123 Street", "NY"));
Person person2 = new Person("John", 30, new Address("123 Street", "NY"));

assertThat(person1)
   .usingRecursiveComparison()
   .isSimilarTo(person2);

This method automatically handles complex object trees without requiring extra boilerplate code, making it ideal for rich domain models and deeply nested objects.

Conclusion

AssertJ offers a wide range of powerful assertions and techniques that can significantly improve the readability and maintainability of your test code. The features discussed in this article - extracting and filtering, soft assertions, describing assertions, field-by-field comparisons, and recursive comparisons - are just a few examples of the many capabilities AssertJ provides.

#java #junit