Skip to content

Commit 49e2035

Browse files
committed
Avoid reporting discovery warnings for abstract methods (#4668)
Resolves #4636. (cherry picked from commit 16d7fa7)
1 parent 90ce5a6 commit 49e2035

File tree

4 files changed

+26
-29
lines changed

4 files changed

+26
-29
lines changed

documentation/src/docs/asciidoc/release-notes/release-notes-5.13.2.adoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ repository on GitHub.
3939
`@Nested`.
4040
* Stop reporting discovery issues for _abstract_ inner classes that contain test methods
4141
but are not annotated with `@Nested`.
42+
* Stop reporting discovery issues for _abstract_ test methods. While they won't be
43+
executed, it's a valid pattern to annotate them with `@Test` for documentation purposes
44+
and override them in subclasses while re-declaring the `@Test` annotation.
4245

4346
[[release-notes-5.13.2-junit-jupiter-deprecations-and-breaking-changes]]
4447
==== Deprecations and Breaking Changes

junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsTestableMethod.java

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
package org.junit.jupiter.engine.discovery.predicates;
1212

1313
import static org.junit.platform.commons.support.AnnotationSupport.isAnnotated;
14+
import static org.junit.platform.commons.support.ModifierSupport.isNotAbstract;
1415

1516
import java.lang.annotation.Annotation;
1617
import java.lang.reflect.Method;
@@ -39,14 +40,13 @@ abstract class IsTestableMethod implements Predicate<Method> {
3940
this.annotationType = annotationType;
4041
this.condition = isNotStatic(annotationType, issueReporter) //
4142
.and(isNotPrivate(annotationType, issueReporter)) //
42-
.and(isNotAbstract(annotationType, issueReporter)) //
4343
.and(returnTypeConditionFactory.apply(annotationType, issueReporter));
4444
}
4545

4646
@Override
4747
public boolean test(Method candidate) {
4848
if (isAnnotated(candidate, this.annotationType)) {
49-
return condition.check(candidate);
49+
return condition.check(candidate) && isNotAbstract(candidate);
5050
}
5151
return false;
5252
}
@@ -63,12 +63,6 @@ private static Condition<Method> isNotPrivate(Class<? extends Annotation> annota
6363
method -> createIssue(annotationType, method, "must not be private"));
6464
}
6565

66-
private static Condition<Method> isNotAbstract(Class<? extends Annotation> annotationType,
67-
DiscoveryIssueReporter issueReporter) {
68-
return issueReporter.createReportingCondition(ModifierSupport::isNotAbstract,
69-
method -> createIssue(annotationType, method, "must not be abstract"));
70-
}
71-
7266
protected static Condition<Method> hasVoidReturnType(Class<? extends Annotation> annotationType,
7367
DiscoveryIssueReporter issueReporter) {
7468
return issueReporter.createReportingCondition(ReflectionUtils::returnsPrimitiveVoid,

jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/DiscoveryTests.java

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,30 +63,30 @@ class DiscoveryTests extends AbstractJupiterTestEngineTests {
6363
@Test
6464
void discoverTestClass() {
6565
LauncherDiscoveryRequest request = defaultRequest().selectors(selectClass(LocalTestCase.class)).build();
66-
TestDescriptor engineDescriptor = discoverTests(request).getEngineDescriptor();
66+
TestDescriptor engineDescriptor = discoverTestsWithoutIssues(request);
6767
assertEquals(7, engineDescriptor.getDescendants().size(), "# resolved test descriptors");
6868
}
6969

7070
@Test
7171
void doNotDiscoverAbstractTestClass() {
7272
LauncherDiscoveryRequest request = defaultRequest().selectors(selectClass(AbstractTestCase.class)).build();
73-
TestDescriptor engineDescriptor = discoverTests(request).getEngineDescriptor();
73+
TestDescriptor engineDescriptor = discoverTestsWithoutIssues(request);
7474
assertEquals(0, engineDescriptor.getDescendants().size(), "# resolved test descriptors");
7575
}
7676

7777
@Test
7878
void discoverMethodByUniqueId() {
7979
LauncherDiscoveryRequest request = defaultRequest().selectors(
8080
selectUniqueId(JupiterUniqueIdBuilder.uniqueIdForMethod(LocalTestCase.class, "test1()"))).build();
81-
TestDescriptor engineDescriptor = discoverTests(request).getEngineDescriptor();
81+
TestDescriptor engineDescriptor = discoverTestsWithoutIssues(request);
8282
assertEquals(2, engineDescriptor.getDescendants().size(), "# resolved test descriptors");
8383
}
8484

8585
@Test
8686
void discoverMethodByUniqueIdForOverloadedMethod() {
8787
LauncherDiscoveryRequest request = defaultRequest().selectors(
8888
selectUniqueId(JupiterUniqueIdBuilder.uniqueIdForMethod(LocalTestCase.class, "test4()"))).build();
89-
TestDescriptor engineDescriptor = discoverTests(request).getEngineDescriptor();
89+
TestDescriptor engineDescriptor = discoverTestsWithoutIssues(request);
9090
assertEquals(2, engineDescriptor.getDescendants().size(), "# resolved test descriptors");
9191
}
9292

@@ -95,7 +95,7 @@ void discoverMethodByUniqueIdForOverloadedMethodVariantThatAcceptsArguments() {
9595
LauncherDiscoveryRequest request = defaultRequest().selectors(
9696
selectUniqueId(JupiterUniqueIdBuilder.uniqueIdForMethod(LocalTestCase.class,
9797
"test4(" + TestInfo.class.getName() + ")"))).build();
98-
TestDescriptor engineDescriptor = discoverTests(request).getEngineDescriptor();
98+
TestDescriptor engineDescriptor = discoverTestsWithoutIssues(request);
9999
assertEquals(2, engineDescriptor.getDescendants().size(), "# resolved test descriptors");
100100
}
101101

@@ -105,7 +105,7 @@ void discoverMethodByMethodReference() throws NoSuchMethodException {
105105

106106
LauncherDiscoveryRequest request = defaultRequest().selectors(
107107
selectMethod(LocalTestCase.class, testMethod)).build();
108-
TestDescriptor engineDescriptor = discoverTests(request).getEngineDescriptor();
108+
TestDescriptor engineDescriptor = discoverTestsWithoutIssues(request);
109109
assertEquals(2, engineDescriptor.getDescendants().size(), "# resolved test descriptors");
110110
}
111111

@@ -114,7 +114,7 @@ void discoverMultipleMethodsOfSameClass() {
114114
LauncherDiscoveryRequest request = defaultRequest().selectors(selectMethod(LocalTestCase.class, "test1"),
115115
selectMethod(LocalTestCase.class, "test2")).build();
116116

117-
TestDescriptor engineDescriptor = discoverTests(request).getEngineDescriptor();
117+
TestDescriptor engineDescriptor = discoverTestsWithoutIssues(request);
118118

119119
assertThat(engineDescriptor.getChildren()).hasSize(1);
120120
TestDescriptor classDescriptor = getOnlyElement(engineDescriptor.getChildren());
@@ -361,14 +361,23 @@ void reportsWarningsForBlankDisplayNames() throws Exception {
361361
.contains(org.junit.platform.engine.support.descriptor.MethodSource.from(method));
362362
}
363363

364+
private TestDescriptor discoverTestsWithoutIssues(LauncherDiscoveryRequest request) {
365+
var results = super.discoverTests(request);
366+
assertThat(results.getDiscoveryIssues()).isEmpty();
367+
return results.getEngineDescriptor();
368+
}
369+
364370
// -------------------------------------------------------------------
365371

366372
@SuppressWarnings("unused")
367-
private static abstract class AbstractTestCase {
373+
static abstract class AbstractTestCase {
368374

369375
@Test
370-
void abstractTest() {
376+
void test() {
371377
}
378+
379+
@Test
380+
abstract void abstractTest();
372381
}
373382

374383
@SuppressWarnings("JUnitMalformedDeclaration")

jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/predicates/IsTestMethodTests.java

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,7 @@ void bogusAbstractTestMethod() {
7272
var method = abstractMethod("bogusAbstractTestMethod");
7373

7474
assertThat(isTestMethod).rejects(method);
75-
76-
var issue = getOnlyElement(discoveryIssues);
77-
assertThat(issue.severity()).isEqualTo(Severity.WARNING);
78-
assertThat(issue.message()).isEqualTo("@Test method '%s' must not be abstract. It will not be executed.",
79-
method.toGenericString());
80-
assertThat(issue.source()).contains(MethodSource.from(method));
75+
assertThat(discoveryIssues).isEmpty();
8176
}
8277

8378
@Test
@@ -86,12 +81,8 @@ void bogusAbstractNonVoidTestMethod() {
8681

8782
assertThat(isTestMethod).rejects(method);
8883

89-
assertThat(discoveryIssues).hasSize(2);
90-
discoveryIssues.sort(comparing(DiscoveryIssue::message));
91-
assertThat(discoveryIssues.getFirst().message()) //
92-
.isEqualTo("@Test method '%s' must not be abstract. It will not be executed.",
93-
method.toGenericString());
94-
assertThat(discoveryIssues.getLast().message()) //
84+
var issue = getOnlyElement(discoveryIssues);
85+
assertThat(issue.message()) //
9586
.isEqualTo("@Test method '%s' must not return a value. It will not be executed.",
9687
method.toGenericString());
9788
}

0 commit comments

Comments
 (0)