BackendBench
Coffee

Unravel โ€บ Java concepts โ€บ Testing

Testing

Advanced JUnit 5 and async assertions

Beyond simple @Test methods, JUnit 5 supports parameterised tests, nested test groups, temporary directories, conditional execution and custom extensions.

Learn these first

At a glance

Mental model

A test lab with a template: instead of writing the same experiment fifty times with different samples, you write it once and feed it a table of samples, and the lab prints a separate result for each.

What happens, in order
  1. 1Parameterised tests: @ParameterizedTest with @CsvSource({"1,2,3", "0,0,0"}), @ValueSource, @EnumSource or @MethodSource("cases") run the same body for each row and report each separately
  2. 2@Nested inner classes group scenarios ("when the cart is empty", "when the cart has items") with shared set-up; @TempDir Path dir gives a clean temporary directory; @Tag("slow") filters runs
  3. 3assertAll(() -> ..., () -> ...) reports every failure instead of stopping at the first; assertThrows returns the exception for further checks; AssertJ (assertThat(list).hasSize(2).extracting(...)) gives fluent, readable assertions
  4. 4await().atMost(5, SECONDS).untilAsserted(() -> assertEquals(3, repo.count())) polls until the condition holds or fails with a clear message, instead of fixed sleeps
Remember
Watch out
Sleeping instead of awaiting a conditionOrder-dependent testsOne assertion failure hiding othersParameterised tests with unreadable data tables
Example (highlighted lines explain it)
@ParameterizedTest@CsvSource({"100,10,90", "50,0,50", "20,100,0"})void appliesDiscount(int price, int percent, int expected) {    assertEquals(expected, Pricing.apply(price, percent));}@Testvoid eventuallyProcessesMessage() {    publisher.publish(new OrderPlaced("o-1"));    await().atMost(5, TimeUnit.SECONDS)        .untilAsserted(() -> assertTrue(orders.exists("o-1")));}
  1. line 1 uses ParameterizedTest, the core of Advanced JUnit 5 and async assertions
  2. line 2 uses CsvSource, the core of Advanced JUnit 5 and async assertions
Read the full explanation (about 2 min)

Beyond simple @Test methods, JUnit 5 supports parameterised tests, nested test groups, temporary directories, conditional execution and custom extensions. Awaitility replaces Thread.sleep for code that finishes asynchronously.

A mental model

A test lab with a template: instead of writing the same experiment fifty times with different samples, you write it once and feed it a table of samples, and the lab prints a separate result for each.

How it works

Parameterised tests: @ParameterizedTest with @CsvSource({"1,2,3", "0,0,0"}), @ValueSource, @EnumSource or @MethodSource("cases") run the same body for each row and report each separately.

@Nested inner classes group scenarios ("when the cart is empty", "when the cart has items") with shared set-up; @TempDir Path dir gives a clean temporary directory; @Tag("slow") filters runs.

assertAll(() -> ..., () -> ...) reports every failure instead of stopping at the first; assertThrows returns the exception for further checks; AssertJ (assertThat(list).hasSize(2).extracting(...)) gives fluent, readable assertions.

await().atMost(5, SECONDS).untilAsserted(() -> assertEquals(3, repo.count())) polls until the condition holds or fails with a clear message, instead of fixed sleeps.

Going deeper

Thread.sleep in tests is either too short (flaky failures) or too long (slow suite). Awaitility finishes as soon as the condition is true and has a bounded timeout.

Each test must be independent of order. Shared mutable state (static fields, databases not cleaned) causes tests to pass alone and fail together; @TestInstance(PER_CLASS) and @Order make this easy to introduce on purpose and by accident.

Custom extensions (ParameterResolver, BeforeEachCallback) are the right place for reusable set-up, replacing base classes and JUnit 4 rules.

Under the hood

The JUnit Platform discovers tests through engines; the Jupiter engine builds a tree of containers and test descriptors from annotations, evaluates conditions, instantiates the test class per method (default) and runs the extension callbacks in a defined order around each phase.

Common mistakes

  • Sleeping instead of awaiting a condition.
  • Order-dependent tests.
  • One assertion failure hiding others.
  • Parameterised tests with unreadable data tables.

How Unravel recognises it

When you paste code, Unravel looks for these signs of advanced junit 5 and async 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 Advanced JUnit 5 and async assertions?

Beyond simple @Test methods, JUnit 5 supports parameterised tests, nested test groups, temporary directories, conditional execution and custom extensions. Awaitility replaces Thread.sleep for code that finishes asynchronously.

What are the most common mistakes with Advanced JUnit 5 and async assertions?

Sleeping instead of awaiting a condition. Order-dependent tests. One assertion failure hiding others. Parameterised tests with unreadable data tables.

How can I see Advanced JUnit 5 and async assertions in real code?

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