JUnit 5 Nested Test Class Mismatch
ID |
java.junit5_inner_test_classes_annotated |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
Java |
Tags |
reliability, testing |
Description
Reports a member class that declares JUnit 5 test methods (@Test, @RepeatedTest, @TestFactory, @TestTemplate or @ParameterizedTest) and gets the @Nested annotation backwards: a non-static inner class missing it, or a static nested class carrying it.
Rationale
@Nested is how JUnit 5 tells an inner class from a plain member class: without it, the engine never instantiates the class and its tests silently never run, even though the class compiles and reads exactly like a working test. The opposite mistake is just as broken — @Nested on a static nested class is rejected, because a static class shares no instance state with its enclosing test, which is the entire point of nesting tests in the first place.
class OrderServiceTest {
class PricingRules { // FLAW — inner test class missing @Nested
@Test
void appliesTierDiscount() {
// never runs — the engine does not know this class holds tests
}
}
@Nested
static class LoyaltyRules { // FLAW — @Nested on a static nested class
@Test
void awardsPoints() {
// rejected: a static class shares no instance state with OrderServiceTest
}
}
static class RefundRules { // OK — static and unannotated
@Test
void refundsWithinWindow() {
}
}
}
Remediation
Annotate the inner class with @Nested, or drop static from a nested class that needs @Nested.
class OrderServiceTest {
@Nested
class PricingRules {
@Test
void appliesTierDiscount() {
// runs as part of OrderServiceTest
}
}
}
What is not reported
An abstract member class is left alone, since it is meant to be extended rather than run directly. A local class declared inside a method body, and an anonymous class body, are both out of scope — neither is a member class JUnit 5 can discover as nested, regardless of @Nested. A class whose only test-shaped methods carry a JUnit 4 or TestNG @Test is left alone too, because @Nested has no effect on either.
This rule does not check whether the build is configured to execute static nested test classes at all (some build/test runner defaults skip them); that is a build configuration concern, not a JUnit 5 usage defect.