Skip to content

Commit d69ceec

Browse files
committed
Avoid reporting discovery warnings for abstract methods
Resolves #4636.
1 parent 09c6a05 commit d69ceec

File tree

4 files changed

+26
-30
lines changed

4 files changed

+26
-30
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ on GitHub.
3535
[[release-notes-5.13.2-junit-jupiter-bug-fixes]]
3636
==== Bug Fixes
3737

38-
* ❓
38+
* Stop reporting discovery issues for _abstract_ test methods. While they won't be
39+
executed, it's a valid pattern to annotate them with `@Test` for documentation purposes
40+
and override them in subclasses while re-declaring the `@Test` annotation.
3941

4042
[[release-notes-5.13.2-junit-jupiter-deprecations-and-breaking-changes]]
4143
==== 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
@@ -12,6 +12,7 @@
1212

1313
import static org.junit.jupiter.engine.support.MethodReflectionUtils.getReturnType;
1414
import static org.junit.platform.commons.support.AnnotationSupport.isAnnotated;
15+
import static org.junit.platform.commons.support.ModifierSupport.isNotAbstract;
1516

1617
import java.lang.annotation.Annotation;
1718
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(method -> getReturnType(method) == void.class,

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
@@ -62,30 +62,30 @@ class DiscoveryTests extends AbstractJupiterTestEngineTests {
6262
@Test
6363
void discoverTestClass() {
6464
LauncherDiscoveryRequest request = defaultRequest().selectors(selectClass(LocalTestCase.class)).build();
65-
TestDescriptor engineDescriptor = discoverTests(request).getEngineDescriptor();
65+
TestDescriptor engineDescriptor = discoverTestsWithoutIssues(request);
6666
assertEquals(7, engineDescriptor.getDescendants().size(), "# resolved test descriptors");
6767
}
6868

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

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

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

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

@@ -104,7 +104,7 @@ void discoverMethodByMethodReference() throws NoSuchMethodException {
104104

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

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

116-
TestDescriptor engineDescriptor = discoverTests(request).getEngineDescriptor();
116+
TestDescriptor engineDescriptor = discoverTestsWithoutIssues(request);
117117

118118
assertThat(engineDescriptor.getChildren()).hasSize(1);
119119
TestDescriptor classDescriptor = getOnlyElement(engineDescriptor.getChildren());
@@ -332,14 +332,23 @@ void reportsWarningsForBlankDisplayNames() throws NoSuchMethodException {
332332
.contains(org.junit.platform.engine.support.descriptor.MethodSource.from(method));
333333
}
334334

335+
private TestDescriptor discoverTestsWithoutIssues(LauncherDiscoveryRequest request) {
336+
var results = super.discoverTests(request);
337+
assertThat(results.getDiscoveryIssues()).isEmpty();
338+
return results.getEngineDescriptor();
339+
}
340+
335341
// -------------------------------------------------------------------
336342

337343
@SuppressWarnings("unused")
338-
private static abstract class AbstractTestCase {
344+
static abstract class AbstractTestCase {
339345

340346
@Test
341-
void abstractTest() {
347+
void test() {
342348
}
349+
350+
@Test
351+
abstract void abstractTest();
343352
}
344353

345354
@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)