Lesson 30 / 38
JUnit 5 In Depth
Use the full assertion toolkit — assertEquals, assertThrows, assertAll — and control setup/teardown per test and per class with JUnit 5's lifecycle annotations.
Lifecycle annotations
@BeforeEach/@AfterEach run around every test method (fresh state, no leakage between tests); @BeforeAll/@AfterAll run once for the whole class and must be static (unless the class uses @TestInstance(PER_CLASS)). Use @BeforeAll only for expensive, read-only setup shared safely across tests.
assertAll and assertThrows
assertAll groups related assertions so all of them run and report even if an earlier one fails — a single assertEquals would stop at the first failure. assertThrows verifies a specific exception type and lets you inspect its message.
@Test
void orderValidation() {
Order o = new Order(-5, "");
assertAll(
() -> assertTrue(o.hasErrors()),
() -> assertEquals(2, o.errorCount())
);
var ex = assertThrows(IllegalArgumentException.class,
() -> new Order(-1, "x"));
assertTrue(ex.getMessage().contains("quantity"));
}Parameterized tests
@ParameterizedTest with @ValueSource, @CsvSource, or @MethodSource runs the same test body once per input, replacing copy-pasted near-identical @Test methods.
@ParameterizedTest
@CsvSource({"2,4", "3,9", "5,25"})
void squares(int in, int expected) {
assertEquals(expected, MathUtil.square(in));
}