Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
JUnit Jupiter’s DisplayNameGenerator lets you make test reports easier to scan without adding @DisplayName to every test. For most teams, ReplaceUnderscores is the simplest default: write descriptive method names with underscores, and JUnit displays them as words. Use IndicativeSentences when nested test classes add useful context, and reserve explicit names for exceptions and parameterized-test invocations.
Display names improve navigation and diagnostics in IDEs, reports, and build output. They do not change test execution, assertions, ordering, or behavior. This guide refers to JUnit Jupiter; check your project’s JUnit version before using newer annotations.
The quickest improvement: replace underscores with spaces
Java method names must be identifiers, so descriptive names often end up awkward in reports. With the default generator, a method such as should_return_true_when_user_is_active may appear with underscores and trailing parentheses. ReplaceUnderscores turns those underscores into spaces:
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
import org.junit.jupiter.api.Test;
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
class User_repository {
@Test
void finds_a_user_by_id() {
}
@Test
void returns_empty_when_the_user_does_not_exist() {
}
}
The report can then show a hierarchy like this:
User repository
├─ finds a user by id
└─ returns empty when the user does not exist
The generator only replaces underscores. It does not split camelCase, fix grammar, or infer what a test means. For readable output, write the test method name as a clear behavioral description and separate its words with underscores.
#1 Best Overall
See the JUnit Jupiter DisplayNameGenerator API and the JUnit 5.13.4 user guide for the documented generator behavior.
Choose the generator that fits the suite
| Generator | What it displays | Best fit |
|---|---|---|
Standard |
JUnit Jupiter’s normal naming behavior. Exact formatting depends on the method signature and test context. | Keep the usual default. |
Simple |
Like Standard, but removes trailing parentheses from no-argument methods. |
Keep camelCase identifiers while dropping empty parentheses. |
ReplaceUnderscores |
Replaces underscores with spaces. | Use descriptive, underscore-separated Java identifiers as readable labels. |
IndicativeSentences |
Combines enclosing-class and method names into a contextual, sentence-like display name. | Show meaningful context from nested test classes. |
Simple is a small cosmetic change, not a prose generator. For example, a method called shouldReturnActiveAccount is displayed without its empty parentheses, but remains camelCase. With Standard, a typical no-argument method may be displayed as shouldReturnActiveAccount().
For most teams, ReplaceUnderscores is the most useful starting point: it is predictable and adds little ceremony. Choose IndicativeSentences when class nesting expresses conditions or domain context that readers need. The available built-ins and their behavior are documented in the JUnit API reference.
Apply a generator locally
Put @DisplayNameGeneration on a test class when that class follows a consistent naming convention. The annotation applies to types and is inherited through superclasses and implemented interfaces; nested test classes also inherit it from their enclosing class. Check the annotation API for its scope and inheritance rules.
Rank #2
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
import org.junit.jupiter.api.Test;
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
class Shopping_cart {
@Test
void adds_an_item_to_the_cart() {
}
@Test
void rejects_an_item_that_is_unavailable() {
}
}
Use a base class or test interface to establish a convention only when you intend its descendants to inherit it. For nested tests, setting the generator on the outer class usually keeps the hierarchy consistent. Avoid mixing generators across a project without a clear reason.
Set a project-wide default
To use the same generator throughout a test project, create src/test/resources/junit-platform.properties and add:
junit.jupiter.displayname.generator.default =
org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores
The property value is the generator’s fully qualified class name. The built-in generators are nested inside DisplayNameGenerator, so the configuration uses $ between the outer class and generator name. In Java annotation syntax, use the nested-class form with .class instead:
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware match@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
A global default is a project convention, not a replacement for choosing names carefully. A class-level @DisplayNameGeneration takes precedence over it. The property and precedence rules are covered in the JUnit user guide.
Know which name wins
For a class or test method, the practical precedence is:
- An explicit
@DisplayNameon that class or method. - An applicable
@DisplayNameGenerationon the class hierarchy. - The
junit.jupiter.displayname.generator.defaultproject setting. DisplayNameGenerator.Standardwhen no other choice applies.
That means an explicit @DisplayName can make a generator appear not to work. If you rename a method and its report label stays the same, look for an explicit display name; it intentionally overrides generated naming.
Parameterized tests have an additional naming layer
A generator names the test method or template, but the name attribute on @ParameterizedTest controls the labels for individual invocations. Configure both when a report needs a readable hierarchy:
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
class Password_validation {
@ParameterizedTest(name = "Input "{0}" is valid: {1}")
@CsvSource({
"'abc123', true",
"'short', false"
})
void validates_password_strength(String input, boolean expected) {
}
}
A report might show the class and method as containers, with invocation labels such as Input "abc123" is valid: true and Input "short" is valid: false. The generator does not replace the parameterized-test name pattern. Keep patterns focused on useful input and expected-result details rather than dumping large object representations.
Rank #4
Use nested tests for context
Nested classes can make conditions explicit while keeping each method name short. With ReplaceUnderscores, the test tree is already useful:
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
class Order_service {
@Nested
class When_the_order_exists {
@Test
void returns_the_order() {
}
}
@Nested
class When_the_order_does_not_exist {
@Test
void returns_an_empty_result() {
}
}
}
The hierarchy can read as:
Order service
├─ When the order exists
│ └─ returns the order
└─ When the order does not exist
└─ returns an empty result
To combine enclosing class and method fragments into a continuous label, use @IndicativeSentencesGeneration:
@IndicativeSentencesGeneration(
separator = " -> ",
generator = DisplayNameGenerator.ReplaceUnderscores.class
)
class Order_service {
@Nested
class When_the_order_exists {
@Test
void returns_the_order() {
}
}
}
This can produce a label such as Order service -> When the order exists -> returns the order. The annotation’s defaults use ", " as the separator and Standard as its fragment generator. Choose a separator your report viewer handles well. Full sentences can be more readable, but long repeated context is harder to scan in CI output. See the IndicativeSentencesGeneration API and IndicativeSentences API.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Use explicit fragments for wording that identifiers cannot express
JUnit Jupiter 5.13.0 introduced @SentenceFragment, which supplies custom text for an individual fragment generated by IndicativeSentences. For example:
Best Value
@IndicativeSentencesGeneration(
separator = " -> ",
generator = DisplayNameGenerator.ReplaceUnderscores.class
)
class Checkout {
@Nested
@SentenceFragment("the payment is declined")
class Payment_is_declined {
@Test
void shows_the_retry_option() {
}
}
}
Use this only when the project’s JUnit Jupiter API includes the annotation. Older JUnit 5 projects may not compile with it. Keep Jupiter dependencies on compatible versions, and confirm the version used by the project; the JUnit 5.13.4 release notes identify @SentenceFragment as a 5.13 feature.
When to use a custom generator
If the built-ins cannot express a stable team convention, you can implement DisplayNameGenerator. A custom generator must implement the interface and provide a default constructor. For a modern API, its methods include enclosing-instance-type information:
import java.lang.reflect.Method;
import java.util.List;
import org.junit.jupiter.api.DisplayNameGenerator;
public final class BusinessDisplayNameGenerator
implements DisplayNameGenerator {
public BusinessDisplayNameGenerator() {
}
@Override
public String generateDisplayNameForClass(Class<?> testClass) {
return humanize(testClass.getSimpleName());
}
@Override
public String generateDisplayNameForNestedClass(
List<Class<?>> enclosingInstanceTypes,
Class<?> nestedClass) {
return humanize(nestedClass.getSimpleName());
}
@Override
public String generateDisplayNameForMethod(
List<Class<?>> enclosingInstanceTypes,
Class<?> testClass,
Method testMethod) {
return humanize(testMethod.getName());
}
private static String humanize(String value) {
return value.replace('_', ' ');
}
}
This example humanizes underscores only; it is a starting point, not a universal grammar engine. Custom logic adds maintenance and compatibility costs. Older examples may use deprecated overloads, so check the Javadoc for the JUnit version targeted by your project before copying an implementation. The current API is documented in the versioned interface reference.
Write names that stay useful
- Describe behavior. Prefer
returns_empty_when_no_matching_users_existtocalls_repository. - Name the relevant condition. For example,
throws_exception_when_token_is_expired. - Keep names stable. A behavior-based name is less likely to become misleading after an implementation change.
- Keep them concise.
preserves_original_order_when_results_are_paginatedis more scannable than encoding every status, header, log, and response detail in one name. - Use a consistent grammatical style. Names such as
works,does_the_thing, andtest1do not tell a reader what passed or failed.
If a method name is getting unwieldy, move context into a nested class, use a concise parameterized invocation name, or give one important case a targeted @DisplayName. Explicit names accept spaces, special characters, and emoji, but terminal output, XML consumers, dashboards, and log parsers may render unusual characters inconsistently. Ordinary text is the safer choice for names consumed by automation.
Troubleshoot a generator that appears not to work
- Check for
@DisplayName. It overrides generated names by design. - Check the property file. Confirm it is
src/test/resources/junit-platform.properties, the key is exactlyjunit.jupiter.displayname.generator.default, and the test runtime includes the test resources. - Check the generator class name. The property uses
org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores; the annotation usesDisplayNameGenerator.ReplaceUnderscores.class. - Check the engine. Jupiter annotations and generators apply to JUnit Jupiter tests, not tests running under JUnit Vintage.
- Separate configuration from rendering. Temporarily annotate a class with
@DisplayNameGeneration. If that works, investigate property loading; if it does not, check imports, dependencies, and the test engine. - Check parameterized invocation names. Set
@ParameterizedTest(name = "...")for individual cases; a display-name generator alone does not set that pattern.
Do not expect identical presentation in every IDE, console launcher, XML report, or CI dashboard. JUnit provides display-name information, while the consuming tool controls how it renders it.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

