Lesson 4 / 25

Assertions, Exceptions and AssertJ

Write precise assertions for values, collections, exceptions and grouped checks.

Saying exactly what you expect

JUnit's Assertions class covers the basics: assertEquals, assertNotEquals, assertTrue/assertFalse, assertNull/assertNotNull, assertSame (identity), assertArrayEquals and assertIterableEquals. assertThrows(Type.class, executable) checks that code throws and returns the exception for further checks; assertDoesNotThrow documents the opposite. assertAll groups several assertions and reports all failures together instead of stopping at the first. assertTimeout fails if code takes too long. For floating point, pass a delta: assertEquals(0.3, sum, 1e-9). Many teams prefer AssertJ for readable, chainable assertions with excellent failure messages: assertThat(list).hasSize(3).containsExactly("a", "b", "c"), assertThat(order.total()).isEqualByComparingTo("499.00") for BigDecimal, assertThatThrownBy(...).isInstanceOf(...).hasMessageContaining(...), and extracting to check fields of objects in collections. Whichever you use, assert the specific outcome that matters, not just that something is non-null.

Precise assertions

Grouped and fluent assertions report exactly which expectations failed.

A checklist with several lines, most ticked and one crossed, all reported together on one panel.
Figure 2.1 — Grouped assertions report every failing expectation.

JUnit and AssertJ assertions

Grouped checks, exceptions, collections and BigDecimal comparisons.

import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertEquals;

@Test
void orderTotalsAreCalculated() {
    Order order = Order.of(line("pen", 2, "49.50"), line("notebook", 1, "120.00"));

    assertAll("order",
        () -> assertEquals(2, order.lines().size()),
        () -> assertThat(order.total()).isEqualByComparingTo("219.00"),   // 219.0 == 219.00
        () -> assertThat(order.status()).isEqualTo(OrderStatus.DRAFT));
}

@Test
void lineSkusAreKeptInOrder() {
    Order order = Order.of(line("pen", 1, "10"), line("ink", 1, "20"));
    assertThat(order.lines())
        .extracting(OrderLine::sku)
        .containsExactly("pen", "ink");
}

@Test
void emptyOrderCannotBePlaced() {
    Order order = Order.of();
    assertThatThrownBy(order::place)
        .isInstanceOf(IllegalStateException.class)
        .hasMessageContaining("at least one line");
}

BigDecimal equals checks scale

new BigDecimal("219.0").equals(new BigDecimal("219.00")) is false because the scales differ. Use AssertJ's isEqualByComparingTo or compare with compareTo when checking money.

Quick check: What does assertAll do differently from separate assertions?

  • It runs assertions in parallel threads
  • It ignores failures
  • It executes all grouped assertions and reports every failure together
  • It only works with AssertJ
Answer

It executes all grouped assertions and reports every failure together — assertAll collects failures instead of stopping at the first failing assertion.