Skip to content

Commit 9b15edd

Browse files
committed
Introduce @UseTechnicalNames for the JUnitPlatform runner
Due to recent changes, technical names were previously used for test methods and their test classes instead of display names. This commit introduces a new @UseTechnicalNames annotation that allows one to opt-in for the usage of technical names instead of display names. If @UseTechnicalNames not directly present on the test class run via the JUnitPlatform runner, display names will be used by default. Closes #379
1 parent 04a0b7f commit 9b15edd

File tree

5 files changed

+131
-28
lines changed

5 files changed

+131
-28
lines changed

documentation/src/docs/asciidoc/release-notes-5.0.0-M1.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ Platform, Jupiter, and Vintage, consult the dedicated subsections.
7474
** `@Packages` has been renamed to `@SelectPackages`.
7575
** `@Classes` has been renamed to `@SelectClasses`.
7676
** `@UniqueIds` has been removed.
77+
** `@UseTechnicalNames` has been introduced.
78+
*** See <<running-tests-junit-platform-runner-technical-names>>.
7779
* The Gradle plugin for the JUnit Platform has been completely overhauled.
7880
** The JUnit Platform Gradle plugin now requires Gradle 2.5 or higher.
7981
** The `junit5Test` Gradle task has been renamed to `junitPlatformTest`.

documentation/src/docs/asciidoc/running-tests.adoc

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -297,10 +297,10 @@ for example, a JUnit Jupiter test class.
297297
Annotating a class with `@RunWith(JUnitPlatform.class)` allows it to be run with IDEs and
298298
build systems that support JUnit 4 but do not yet support the JUnit Platform directly.
299299

300-
NOTE: Since the JUnit Platform has features that JUnit 4 does not have, the runner is only able
301-
to support a subset of the JUnit Platform functionality, especially with regard to
302-
reporting. But for the time being the `JUnitPlatform` runner is an easy way to get
303-
started.
300+
NOTE: Since the JUnit Platform has features that JUnit 4 does not have, the runner is
301+
only able to support a subset of the JUnit Platform functionality, especially with regard
302+
to reporting (see <<running-tests-junit-platform-runner-technical-names>>). But for the
303+
time being the `JUnitPlatform` runner is an easy way to get started.
304304

305305
[[running-tests-junit-platform-runner-setup]]
306306
==== Setup
@@ -313,6 +313,17 @@ versions.
313313
* `junit-platform-runner` in _test_ scope: location of the `JUnitPlatform` runner
314314
* `junit-jupiter-engine` in _test runtime_ scope: implementation of the Engine API for JUnit Jupiter
315315

316+
[[running-tests-junit-platform-runner-technical-names]]
317+
==== Display Names vs. Technical Names
318+
319+
By default, _display names_ will be used for test artifacts; however, when the
320+
`JUnitPlatform` runner is used to execute tests with a build tool such as Gradle or
321+
Maven, the generated test report often needs to include the _technical names_ of test
322+
artifacts — for example, fully qualified class names — instead of shorter display names
323+
like the simple name of a test class or a custom display name containing special
324+
characters. To enable technical names for reporting purposes, simply declare the
325+
`@UseTechnicalNames` annotation alongside `@RunWith(JUnitPlatform.class)`.
326+
316327
[[running-tests-junit-platform-runner-single-test]]
317328
==== Single Test Class
318329

junit-platform-runner/src/main/java/org/junit/platform/runner/JUnitPlatformTestTree.java

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,12 @@ class JUnitPlatformTestTree {
3838

3939
private final Map<TestIdentifier, Description> descriptions = new HashMap<>();
4040
private final TestPlan plan;
41+
private final boolean useTechnicalNames;
4142
private final Description suiteDescription;
4243

4344
JUnitPlatformTestTree(TestPlan plan, Class<?> testClass) {
4445
this.plan = plan;
46+
this.useTechnicalNames = testClass.isAnnotationPresent(UseTechnicalNames.class);
4547
this.suiteDescription = generateSuiteDescription(plan, testClass);
4648
}
4749

@@ -79,57 +81,68 @@ private void buildDescription(TestIdentifier identifier, Description parent, Tes
7981

8082
private Description createJUnit4Description(TestIdentifier identifier, TestPlan testPlan) {
8183
if (identifier.isTest()) {
82-
String className = getClassName(identifier, testPlan);
83-
String name = getName(identifier);
84-
return Description.createTestDescription(className, name, identifier.getUniqueId());
84+
String containerName;
85+
String name;
86+
87+
if (this.useTechnicalNames) {
88+
containerName = getTechnicalContainerName(identifier, testPlan);
89+
name = getTechnicalName(identifier);
90+
}
91+
else {
92+
containerName = testPlan.getParent(identifier).orElse(identifier).getDisplayName();
93+
name = identifier.getDisplayName();
94+
}
95+
96+
return Description.createTestDescription(containerName, name, identifier.getUniqueId());
8597
}
8698
else {
87-
return Description.createSuiteDescription(identifier.getDisplayName(), identifier.getUniqueId());
99+
String name = (this.useTechnicalNames ? getTechnicalName(identifier) : identifier.getDisplayName());
100+
return Description.createSuiteDescription(name, identifier.getUniqueId());
88101
}
89102
}
90103

91-
private String getName(TestIdentifier testIdentifier) {
104+
private String getTechnicalContainerName(TestIdentifier testIdentifier, TestPlan testPlan) {
92105
Optional<TestSource> optionalSource = testIdentifier.getSource();
93106
if (optionalSource.isPresent()) {
94107
TestSource source = optionalSource.get();
95108
if (source instanceof JavaClassSource) {
96109
return ((JavaClassSource) source).getJavaClass().getName();
97110
}
98111
else if (source instanceof JavaMethodSource) {
99-
JavaMethodSource javaMethodSource = (JavaMethodSource) source;
100-
List<Class<?>> parameterTypes = javaMethodSource.getJavaMethodParameterTypes();
101-
if (parameterTypes.size() == 0) {
102-
return javaMethodSource.getJavaMethodName();
103-
}
104-
else {
105-
return String.format("%s(%s)", javaMethodSource.getJavaMethodName(), StringUtils.nullSafeToString(
106-
Class::getName, parameterTypes.toArray(new Class<?>[parameterTypes.size()])));
107-
}
112+
return ((JavaMethodSource) source).getJavaClass().getName();
108113
}
109114
}
110115

111-
// Else fall back to display name
112-
return testIdentifier.getDisplayName();
116+
// Else fall back to display name of parent
117+
// @formatter:off
118+
return testPlan.getParent(testIdentifier)
119+
.map(TestIdentifier::getDisplayName)
120+
.orElse("<unrooted>");
121+
// @formatter:on
113122
}
114123

115-
private String getClassName(TestIdentifier testIdentifier, TestPlan testPlan) {
124+
private String getTechnicalName(TestIdentifier testIdentifier) {
116125
Optional<TestSource> optionalSource = testIdentifier.getSource();
117126
if (optionalSource.isPresent()) {
118127
TestSource source = optionalSource.get();
119128
if (source instanceof JavaClassSource) {
120129
return ((JavaClassSource) source).getJavaClass().getName();
121130
}
122131
else if (source instanceof JavaMethodSource) {
123-
return ((JavaMethodSource) source).getJavaClass().getName();
132+
JavaMethodSource javaMethodSource = (JavaMethodSource) source;
133+
List<Class<?>> parameterTypes = javaMethodSource.getJavaMethodParameterTypes();
134+
if (parameterTypes.size() == 0) {
135+
return javaMethodSource.getJavaMethodName();
136+
}
137+
else {
138+
return String.format("%s(%s)", javaMethodSource.getJavaMethodName(), StringUtils.nullSafeToString(
139+
Class::getName, parameterTypes.toArray(new Class<?>[parameterTypes.size()])));
140+
}
124141
}
125142
}
126143

127-
// Else fall back to display name of parent
128-
// @formatter:off
129-
return testPlan.getParent(testIdentifier)
130-
.map(TestIdentifier::getDisplayName)
131-
.orElse("<unrooted>");
132-
// @formatter:on
144+
// Else fall back to display name
145+
return testIdentifier.getDisplayName();
133146
}
134147

135148
Set<TestIdentifier> getTestsInSubtree(TestIdentifier ancestor) {
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright 2015-2016 the original author or authors.
3+
*
4+
* All rights reserved. This program and the accompanying materials are
5+
* made available under the terms of the Eclipse Public License v1.0 which
6+
* accompanies this distribution and is available at
7+
*
8+
* http://www.eclipse.org/legal/epl-v10.html
9+
*/
10+
11+
package org.junit.platform.runner;
12+
13+
import static org.junit.platform.commons.meta.API.Usage.Maintained;
14+
15+
import java.lang.annotation.Documented;
16+
import java.lang.annotation.ElementType;
17+
import java.lang.annotation.Inherited;
18+
import java.lang.annotation.Retention;
19+
import java.lang.annotation.RetentionPolicy;
20+
import java.lang.annotation.Target;
21+
22+
import org.junit.platform.commons.meta.API;
23+
24+
/**
25+
* {@code @UseTechnicalNames} specifies that <em>technical names</em> should be
26+
* used instead of <em>display names</em> when running a test suite via
27+
* {@code @RunWith(JUnitPlatform.class)}.
28+
*
29+
* <p>By default, <em>display names</em> will be used for test artifacts; however,
30+
* when the {@link JUnitPlatform} runner is used to execute tests with a build
31+
* tool such as Gradle or Maven, the generated test report often needs to include
32+
* the <em>technical names</em> of test artifacts &mdash; for example, fully
33+
* qualified class names &mdash; instead of shorter <em>display names</em> like
34+
* the simple name of a test class or a custom display name containing special
35+
* characters. To enable <em>technical names</em>, simply declare the
36+
* {@code @UseTechnicalNames} annotation alongside {@code @RunWith(JUnitPlatform.class)}.
37+
*
38+
* @since 1.0
39+
* @see JUnitPlatform
40+
*/
41+
@Retention(RetentionPolicy.RUNTIME)
42+
@Target(ElementType.TYPE)
43+
@Inherited
44+
@Documented
45+
@API(Maintained)
46+
public @interface UseTechnicalNames {
47+
}

platform-tests/src/test/java/org/junit/platform/runner/JUnitPlatformRunnerTests.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,32 @@ void descriptionForJavaMethodSource() throws Exception {
401401
Description engineDescription = children.get(0);
402402
assertEquals("dummy", engineDescription.getDisplayName());
403403

404+
children = engineDescription.getChildren();
405+
assertEquals(1, children.size());
406+
Description testDescription = children.get(0);
407+
// @formatter:off
408+
assertAll(
409+
() -> assertEquals("dummy", testDescription.getClassName(), "class name"),
410+
() -> assertEquals("failingTest", testDescription.getMethodName(), "method name"),
411+
() -> assertEquals("failingTest(dummy)", testDescription.getDisplayName(), "display name")
412+
);
413+
// @formatter:on
414+
}
415+
416+
@Test
417+
void descriptionForJavaMethodSourceUsingTechnicalNames() throws Exception {
418+
DummyTestEngine engine = new DummyTestEngine("dummy");
419+
Method failingTest = getClass().getDeclaredMethod("failingTest");
420+
engine.addTest(failingTest, () -> {
421+
});
422+
423+
JUnitPlatform platformRunner = new JUnitPlatform(TestClassWithTechnicalNames.class, createLauncher(engine));
424+
425+
ArrayList<Description> children = platformRunner.getDescription().getChildren();
426+
assertEquals(1, children.size());
427+
Description engineDescription = children.get(0);
428+
assertEquals("dummy", engineDescription.getDisplayName());
429+
404430
children = engineDescription.getChildren();
405431
assertEquals(1, children.size());
406432
Description testDescription = children.get(0);
@@ -449,6 +475,10 @@ private LauncherDiscoveryRequest instantiateRunnerAndCaptureGeneratedRequest(Cla
449475
private static class TestClass {
450476
}
451477

478+
@UseTechnicalNames
479+
private static class TestClassWithTechnicalNames {
480+
}
481+
452482
private static class DynamicTestEngine implements TestEngine {
453483

454484
@Override

0 commit comments

Comments
 (0)