BackendBench
Coffee

Unravel › Java concepts › Testing

Testing

AssertJ fluent assertions

AssertJ makes test assertions read like sentences: assertThat(orders).hasSize(2).extracting(Order::id).containsExactly(1, 2).

Learn these first

At a glance

Mental model

Instead of a bare "check" stamp, a proofreader who writes in the margin: "line 3 should be 42 but is 41".

What happens, in order
  1. 1Start with assertThat(actual) (a static import from org.assertj.core.api.Assertions) and chain checks: isEqualTo, isNotNull, contains, startsWith, isBetween, isCloseTo(1.0, within(0.01))
  2. 2Collections: hasSize, containsExactly (order matters), containsExactlyInAnyOrder, extracting("name"), allMatch(...), noneMatch(...)
  3. 3Exceptions: assertThatThrownBy(() -> service.find(0)).isInstanceOf(NotFoundException.class).hasMessageContaining("0")
  4. 4usingRecursiveComparison().isEqualTo(expected) compares objects field by field without needing equals
Remember
Watch out
Building an assertion but forgetting the final check (assertThat(x) alone asserts nothing)Using containsExactly when order does not matterMixing JUnit and AssertJ assertion styles in the same test class
Example (highlighted lines explain it)
import static org.assertj.core.api.Assertions.*;import java.util.List;import org.junit.jupiter.api.Test;class OrderTest {  record Order(int id, String customer) {}  @Test  void ordersAreFound() {    List<Order> orders = List.of(new Order(1, "ann"), new Order(2, "bob"));    assertThat(orders).hasSize(2).extracting(Order::customer).containsExactly("ann", "bob");    assertThatThrownBy(() -> orders.get(5)).isInstanceOf(IndexOutOfBoundsException.class);  }}
  1. line 9 uses hasSize, the core of AssertJ fluent assertions
  2. line 10 uses assertThatThrownBy, the core of AssertJ fluent assertions
Read the full explanation (about 1 min)

AssertJ makes test assertions read like sentences: assertThat(orders).hasSize(2).extracting(Order::id).containsExactly(1, 2). Failure messages show exactly what differed.

A mental model

Instead of a bare "check" stamp, a proofreader who writes in the margin: "line 3 should be 42 but is 41".

How it works

Start with assertThat(actual) (a static import from org.assertj.core.api.Assertions) and chain checks: isEqualTo, isNotNull, contains, startsWith, isBetween, isCloseTo(1.0, within(0.01)).

Collections: hasSize, containsExactly (order matters), containsExactlyInAnyOrder, extracting("name"), allMatch(...), noneMatch(...).

Exceptions: assertThatThrownBy(() -> service.find(0)).isInstanceOf(NotFoundException.class).hasMessageContaining("0").

usingRecursiveComparison().isEqualTo(expected) compares objects field by field without needing equals.

Going deeper

The IDE completes the available checks for the type under test, so you discover the API by typing a dot. This is its main advantage over JUnit's assertEquals(expected, actual), which is easy to write with the arguments swapped.

Use SoftAssertions to report all failures of a test at once. Name the failing check with .as("order total").

Assertion style does not replace good tests: assert on behaviour (results, state, interactions), not on internal details.

Under the hood

assertThat is overloaded per type and returns a specific assertion class (ListAssert, StringAssert...), each a fluent builder that throws an AssertionError with a detailed diff on the first failed check.

Common mistakes

  • Building an assertion but forgetting the final check (assertThat(x) alone asserts nothing).
  • Using containsExactly when order does not matter.
  • Mixing JUnit and AssertJ assertion styles in the same test class.

How Unravel recognises it

When you paste code, Unravel looks for these signs of assertj fluent assertions. Spotting them yourself is a good habit when you read unfamiliar code:

Part of a learning path

Related concepts

Frequently asked questions

What is AssertJ fluent assertions?

AssertJ makes test assertions read like sentences: assertThat(orders).hasSize(2).extracting(Order::id).containsExactly(1, 2). Failure messages show exactly what differed.

What are the most common mistakes with AssertJ fluent assertions?

Building an assertion but forgetting the final check (assertThat(x) alone asserts nothing). Using containsExactly when order does not matter. Mixing JUnit and AssertJ assertion styles in the same test class.

How can I see AssertJ fluent assertions in real code?

Paste your own Java into Unravel and it will point out where assertj fluent assertions appears, explain how it works at the detail level you choose, and draw the flow of the code around it.