skip to content

How do @Nested classes combine with @DisplayName and the IndicativeSentences generator to produce readable, hierarchical test reports?

level: seniorimportance: nice to knowfreq 30%

answer

  1. @Nested → hierarchical report tree
  2. Each level can have its own @DisplayName
  3. IndicativeSentences joins enclosing names + method into a sentence
  4. @IndicativeSentencesGeneration(separator=, generator=)
  5. Explicit @DisplayName overrides any generated segment

basics

~10 s

@Nested groups related tests into inner classes, each able to carry its own @DisplayName, so reports read as a tree. IndicativeSentences joins the enclosing names with the method name into one readable sentence.

solid answer

~50 s

@Nested inner classes let you group tests so the report renders a hierarchy: outer class > nested class > method. Each level can have its own @DisplayName, producing readable paths like "Shopping cart > when empty > rejects checkout". The IndicativeSentences DisplayNameGenerator takes this further by concatenating the enclosing display names with the method's name into a single sentence, joined by a separator (default ", "), and it uses another generator (default ReplaceUnderscores) to format each part. You configure its separator and the underlying generator via @IndicativeSentencesGeneration(separator=..., generator=...). This is powerful for BDD-style specs where the class names set the context ("A new account") and methods state the behavior ("has a zero balance"), yielding "A new account, has a zero balance". Explicit @DisplayName still overrides any generated part, so you can fix up wording where the convention reads awkwardly while keeping the rest automatic.

go deeper

for a junior

Knows @Nested groups tests and that each group can have a @DisplayName.

for a middle

Builds a readable report tree with @Nested + @DisplayName and recognizes IndicativeSentences output.

for a senior

Configures IndicativeSentences (separator/delegate), explains precedence with explicit names, and judges when sentence-style helps vs. clutters.

for a principal

Establishes a suite-wide spec-style naming convention, standardizes generator config, and weighs readability, tooling/checkstyle friction, and onboarding cost.

## Building blocks - **`@Nested`** marks a non-static inner class inside a test class as a nested test group. JUnit runs its tests with access to the outer instance's state, and — crucially here — **renders them under the outer class** in the report, forming a tree. - Each nesting level (outer class, nested class, method) can have its own **`@DisplayName`**, so the report path reads naturally. ```java @DisplayName("Shopping cart") class ShoppingCartTest { @Nested @DisplayName("when empty") class WhenEmpty { @Test @DisplayName("rejects checkout") void rejectsCheckout() { } } } ``` Report tree: ``` Shopping cart when empty rejects checkout ``` ## IndicativeSentences — from tree to sentence `DisplayNameGenerator.IndicativeSentences` produces, for each **method**, a single **sentence** by concatenating the *enclosing* display names (outer class, then nested classes) with the method's generated name, separated by a separator string (default `", "`). Each individual piece is itself produced by a *delegate* generator (default `ReplaceUnderscores`). So with method `has_a_zero_balance` inside a `@Nested` class displayed as "A new account": ``` A new account, has a zero balance ``` The enclosing names act as the *subject/context*; the method states the *behavior* — this is why it's called "indicative sentences" and why it pairs well with BDD-style specs. ## Configuring it Apply and tune it with two annotations: ```java @DisplayNameGeneration(DisplayNameGenerator.IndicativeSentences.class) @IndicativeSentencesGeneration( separator = " -> ", generator = DisplayNameGenerator.ReplaceUnderscores.class) class AccountTest { /* ... */ } ``` - `separator` — the string placed between the joined parts. - `generator` — the delegate that formats each part (so you can choose `ReplaceUnderscores`, `Simple`, `Standard`, or a custom one). These settings, like `@DisplayNameGeneration`, **propagate to nested classes**. ## Precedence still holds An explicit **`@DisplayName`** on any element overrides the generated piece for that element. With `IndicativeSentences`, putting `@DisplayName` on a *method* replaces the whole generated sentence for that method; putting it on a *nested class* changes the context segment used in the sentences of its methods. This lets you keep automatic derivation everywhere and hand-tune the few names that read awkwardly. ## Trade-offs to weigh (senior judgment) - **Pros:** reports read like an executable specification; less boilerplate than `@DisplayName` on every method; the structure mirrors behavior. - **Cons:** long sentences can get unwieldy with deep nesting; underscore-driven method names can clash with checkstyle/IDE conventions; mixing generated and explicit names inconsistently hurts uniformity. Decide on one convention and apply it suite-wide (often via the default config parameter). Key terms: **BDD** (Behavior-Driven Development) describes tests as readable behavior statements; a **delegate generator** is the generator IndicativeSentences calls to format each individual segment.

  • What does IndicativeSentences use to format each individual part of the sentence?
    A delegate DisplayNameGenerator, by default ReplaceUnderscores, configurable via @IndicativeSentencesGeneration(generator=...).
  • How do you change the separator between the joined parts?
    Set @IndicativeSentencesGeneration(separator="...") on the class; the default is ", ".
  • Why must @Nested classes be non-static?
    They share the outer test instance's lifecycle and state, which requires a non-static inner class so each has an enclosing instance.

saying these in an interview costs you the question

  • Thinking IndicativeSentences ignores enclosing class names — it concatenates them
  • Forgetting @Nested classes must be non-static inner classes
  • Assuming the separator/generator must be set per nested class (they propagate)
  • Believing deep nesting has no readability cost

context