Baike.dev
All toolsAI codingTrendingOpen sourceNewsSubmit
Log in
Back to tool/Back to issues
#6041·junit-framework

Invocations of a @ParameterizedClass are indistinguishable in reports that show one name per test case

Author: vlsiCreated Sep 7, 2026Updated Sep 11, 2026
Labelsstatus: team discussiontheme: reportingcomponent: Jupiter3rd-party: Gradletheme: parameterized tests

What happens

java
@ParameterizedClass
@ValueSource(booleans = {true, false})
class ParameterizedClassNamesTest {

    ParameterizedClassNamesTest(boolean flag) {
    }

    @ParameterizedTest
    @ValueSource(strings = {"x", "y"})
    void methodInParameterizedClass(String value) {
    }
}

Four test cases run. Compiled with -parameters, their display names are:

[1] value = "x"
[2] value = "y"
[1] value = "x"
[2] value = "y"

Nothing says whether a row ran with flag = true or with flag = false, so a report that shows one name per test case has two names for four cases. Here is Gradle's JUnit XML for exactly this class:

xml
<testcase name="[1] value = &quot;x&quot;" classname="example.ParameterizedClassNamesTest"/>
<testcase name="[2] value = &quot;y&quot;" classname="example.ParameterizedClassNamesTest"/>
<testcase name="[1] value = &quot;x&quot;" classname="example.ParameterizedClassNamesTest"/>
<testcase name="[2] value = &quot;y&quot;" classname="example.ParameterizedClassNamesTest"/>

When one of the four fails, the report does not say which. JUnit knows the value: it renders the class invocation as [1] flag = true on the container one level up. That level does not reach the name of the invocation.

Even junit.jupiter.params.displayname.default does not fix it

junit.jupiter.params.displayname.default = {displayName} [{index}] {argumentSetNameOrArgumentsWithNames}

gives

methodInParameterizedClass(String) [1] value = "x"
methodInParameterizedClass(String) [2] value = "y"
methodInParameterizedClass(String) [1] value = "x"
methodInParameterizedClass(String) [2] value = "y"

The method name is back and the class argument is still missing, because {displayName} expands to the enclosing method rather than to the class invocation, and no other placeholder reaches it. @ParameterizedClass(name = "...") names the class-invocation container, which a consumer that shows one name per test case does not see.

So a user of @ParameterizedClass has no way to make these four cases tell themselves apart, whatever they configure.

What I would like

The default display name of an invocation under a @ParameterizedClass distinguishes the class arguments, so that a build that configures nothing gets a readable report:

[1] flag = true > methodInParameterizedClass(String) [1] value = "x"

or any rendering that carries the same values. Changing a default changes what every existing build prints, so if that is too much, a placeholder for the enclosing invocation would at least make it configurable:

junit.jupiter.params.displayname.default = {enclosingDisplayName} > {displayName} [{index}] {argumentSetNameOrArgumentsWithNames}

Depth is the open question. A parameterized class also runs its @Nested classes, so an invocation can sit more than one level below the parameterized declaration, and a single-level placeholder would not always be enough. Joining the whole ancestry with > is what XmlReportWriter does since #5524, so that rendering would be consistent with what JUnit already writes elsewhere.

Why this is not a report-format issue

JUnit's own reports are unambiguous, and both fixes are recent:

  • #5441 puts the class-invocation index into the legacy reporting name, so junit-platform-reporting writes methodInParameterizedClass(String)[1][1] through [2][2].
  • #5524 writes the display names of all ancestors into the display-name: line of <system-out>, giving ParameterizedClassNamesTest > [1] flag = true > methodInParameterizedClass(String) > [1] value = "x".

I verified both on 6.1.3 and on main built from source.

The gap is for a consumer that has only the leaf display name. Gradle's JUnit XML report is one: it writes the display name into <testcase name>, drops the class-invocation container, and emits no unique id, so [1] value = "x" is all a reader gets. I filed that as gradle/gradle#39079, and Gradle can fix its side from the TestPlan without any change here. What Gradle cannot give me is a report that is readable by default, or a way to make it readable from my own build today.

Backport

If this is accepted, please consider releases/5.14.x as well. We are on the 5.x line and cannot move to 6 yet. #5524 was backported there and shipped in 5.14.4, so the branch is still taking changes in this area. @ParameterizedClass is still marked experimental, which I take to mean its display names are not frozen yet.

Versions

junit-jupiter 6.1.3 and main at commit 9c04c8085, JDK 21.0.9, compiled with -parameters, reproduced through Gradle 9.7.1 and through junit-platform-console-standalone.

Source: junit-team/junit-framework

View original on GitHubView discussion on GitHub