Skip to content

Commit 1871441

Browse files
committed
Improve error message for non-inner @Nested classes
1 parent 3d5a35c commit 1871441

File tree

3 files changed

+34
-8
lines changed

3 files changed

+34
-8
lines changed

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import static org.junit.platform.commons.support.ModifierSupport.isAbstract;
1616
import static org.junit.platform.commons.support.ModifierSupport.isNotAbstract;
1717
import static org.junit.platform.commons.support.ModifierSupport.isNotPrivate;
18+
import static org.junit.platform.commons.util.ReflectionUtils.isInnerClass;
1819
import static org.junit.platform.commons.util.ReflectionUtils.isMethodPresent;
1920
import static org.junit.platform.commons.util.ReflectionUtils.isNestedClassPresent;
2021

@@ -99,12 +100,16 @@ private static Condition<Class<?>> isNotLocal(DiscoveryIssueReporter issueReport
99100
}
100101

101102
private static Condition<Class<?>> isInner(DiscoveryIssueReporter issueReporter) {
102-
return issueReporter.createReportingCondition(ReflectionUtils::isInnerClass,
103-
testClass -> createIssue("@Nested", testClass, "must be an inner class but is static"));
103+
return issueReporter.createReportingCondition(ReflectionUtils::isInnerClass, testClass -> {
104+
if (testClass.getEnclosingClass() == null) {
105+
return createIssue("@Nested", testClass, "must not be a top-level class");
106+
}
107+
return createIssue("@Nested", testClass, "must not be static");
108+
});
104109
}
105110

106111
private static Condition<Class<?>> isNotInner(DiscoveryIssueReporter issueReporter) {
107-
return issueReporter.createReportingCondition(testClass -> !ReflectionUtils.isInnerClass(testClass),
112+
return issueReporter.createReportingCondition(testClass -> !isInnerClass(testClass),
108113
testClass -> createIssue("Test", testClass, "must not be an inner class unless annotated with @Nested"));
109114
}
110115

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,10 +249,10 @@ void reportsWarningForInvalidNestedTestClass(LauncherDiscoveryRequest request) {
249249
var discoveryIssues = results.getDiscoveryIssues().stream().sorted(comparing(DiscoveryIssue::message)).toList();
250250
assertThat(discoveryIssues).hasSize(2);
251251
assertThat(discoveryIssues.getFirst().message()) //
252-
.isEqualTo("@Nested class '%s' must be an inner class but is static. It will not be executed.",
252+
.isEqualTo("@Nested class '%s' must not be private. It will not be executed.",
253253
InvalidTestCases.InvalidTestClassTestCase.Inner.class.getName());
254254
assertThat(discoveryIssues.getLast().message()) //
255-
.isEqualTo("@Nested class '%s' must not be private. It will not be executed.",
255+
.isEqualTo("@Nested class '%s' must not be static. It will not be executed.",
256256
InvalidTestCases.InvalidTestClassTestCase.Inner.class.getName());
257257
}
258258

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

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,21 @@ void staticNestedClassEvaluatesToFalse() {
254254
assertThat(predicates.isAnnotatedWithNestedAndValid).rejects(candidate);
255255

256256
var issue = DiscoveryIssue.builder(Severity.WARNING,
257-
"@Nested class '%s' must be an inner class but is static. It will not be executed.".formatted(
257+
"@Nested class '%s' must not be static. It will not be executed.".formatted(candidate.getName())) //
258+
.source(ClassSource.from(candidate)) //
259+
.build();
260+
assertThat(discoveryIssues.stream().distinct()).containsExactly(issue);
261+
}
262+
263+
@Test
264+
void topLevelClassEvaluatesToFalse() {
265+
var candidate = InvalidTopLevelNestedTestClass.class;
266+
assertThat(predicates.isAnnotatedWithNested).accepts(candidate);
267+
assertFalse(predicates.isValidNestedTestClass(candidate));
268+
assertThat(predicates.isAnnotatedWithNestedAndValid).rejects(candidate);
269+
270+
var issue = DiscoveryIssue.builder(Severity.WARNING,
271+
"@Nested class '%s' must not be a top-level class. It will not be executed.".formatted(
258272
candidate.getName())) //
259273
.source(ClassSource.from(candidate)) //
260274
.build();
@@ -298,8 +312,7 @@ class LocalClass {
298312
assertThat(predicates.isAnnotatedWithNestedAndValid).rejects(candidate);
299313

300314
var issue = DiscoveryIssue.builder(Severity.WARNING,
301-
"@Nested class '%s' must be an inner class but is static. It will not be executed.".formatted(
302-
candidate.getName())) //
315+
"@Nested class '%s' must not be static. It will not be executed.".formatted(candidate.getName())) //
303316
.source(ClassSource.from(candidate)) //
304317
.build();
305318
assertThat(discoveryIssues.stream().distinct()).containsExactly(issue);
@@ -469,3 +482,11 @@ void second() {
469482

470483
}
471484
}
485+
486+
@SuppressWarnings("NewClassNamingConvention")
487+
@Nested
488+
class InvalidTopLevelNestedTestClass {
489+
@Test
490+
void test() {
491+
}
492+
}

0 commit comments

Comments
 (0)