Nested class lifecycle in JUnit - Build an Automation Script
import org.junit.jupiter.api.*; import java.util.ArrayList; import java.util.List; @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class NestedLifecycleTest { private final List<String> lifecycleOrder = new ArrayList<>(); @BeforeAll static void beforeAllTop() { System.out.println("Top-level BeforeAll"); } @AfterAll static void afterAllTop() { System.out.println("Top-level AfterAll"); } @BeforeEach void beforeEachTop() { lifecycleOrder.add("Top BeforeEach"); } @AfterEach void afterEachTop() { lifecycleOrder.add("Top AfterEach"); } @Nested class InnerNested { @BeforeEach void beforeEachNested() { lifecycleOrder.add("Nested BeforeEach"); } @AfterEach void afterEachNested() { lifecycleOrder.add("Nested AfterEach"); } @Test void nestedTest() { lifecycleOrder.add("Nested Test"); Assertions.assertTrue(true); } } @Test void verifyLifecycleOrder() { // Run nested test manually to capture lifecycle order InnerNested nested = new InnerNested(); nested.beforeEachNested(); nested.nestedTest(); nested.afterEachNested(); // Top-level beforeEach and afterEach should be called around nested test // Simulate top-level lifecycle calls beforeEachTop(); afterEachTop(); // Check that lifecycleOrder contains expected sequence List<String> expectedOrder = List.of( "Top BeforeEach", "Nested BeforeEach", "Nested Test", "Nested AfterEach", "Top AfterEach" ); Assertions.assertEquals(expectedOrder, lifecycleOrder); } }
This test class demonstrates the lifecycle of JUnit 5 nested classes.
The NestedLifecycleTest class has lifecycle methods annotated with @BeforeAll, @AfterAll, @BeforeEach, and @AfterEach. The nested class InnerNested also has @BeforeEach and @AfterEach methods and a test method.
We use a List<String> to record the order of lifecycle method calls and the test execution.
The verifyLifecycleOrder test method manually calls the nested lifecycle methods and test to simulate the order and then asserts the recorded order matches the expected sequence.
This approach helps verify the nested class lifecycle behavior clearly and ensures the test passes if the lifecycle methods run in the correct order.
Now add data-driven testing to the nested test method with 3 different input strings verifying they are not empty
Practice
@Nested class inside a test class?Solution
Step 1: Understand the role of @Nested
The@Nestedannotation allows grouping related test methods inside inner classes to organize tests logically.Step 2: Compare other options
The other options describe unrelated features: disabling tests temporarily, running tests in parallel automatically, and creating separate test suite files, which are not the purpose of@Nested.Final Answer:
To group related tests together for better organization -> Option AQuick Check:
@Nested groups tests = C [OK]
- Thinking @Nested runs tests in parallel
- Confusing @Nested with @Disabled
- Assuming @Nested creates separate test files
@Nested class?Solution
Step 1: Identify lifecycle annotations for nested classes
In JUnit 5,@BeforeAllruns once before all tests in the class, including nested classes if used inside them.Step 2: Differentiate from other annotations
@BeforeEachruns before each test method, not once;@AfterEachand@AfterAllrun after tests, so they don't fit the requirement.Final Answer:
@BeforeAll -> Option AQuick Check:
Run once before all tests = @BeforeAll [OK]
- Using @BeforeEach instead of @BeforeAll for once-only setup
- Confusing @AfterAll with setup annotations
- Not placing @BeforeAll inside nested class
class OuterTest {
@BeforeAll
static void setupOuter() { System.out.println("Outer setup"); }
@Nested
class InnerTest {
@BeforeAll
static void setupInner() { System.out.println("Inner setup"); }
@Test
void testOne() { System.out.println("Test one"); }
}
}
What will be the order of printed lines when running testOne()?Solution
Step 1: Understand lifecycle order in nested classes
The@BeforeAllin the outer class runs first, then the@BeforeAllin the nested class, followed by the test method.Step 2: Trace the print statements
First prints "Outer setup", then "Inner setup", then "Test one" as per the method calls.Final Answer:
Outer setup\nInner setup\nTest one -> Option BQuick Check:
Outer before all, then inner before all, then test [OK]
- Assuming nested @BeforeAll runs before outer
- Mixing order of test and setup prints
- Forgetting static requirement for @BeforeAll in nested
@BeforeAll from running?
class OuterTest {
@Nested
class InnerTest {
@BeforeAll
void setup() { System.out.println("Setup"); }
@Test
void test() { System.out.println("Test"); }
}
}Solution
Step 1: Check @BeforeAll method requirements in nested classes
In JUnit 5,@BeforeAllmethods inside nested classes must be static unless the nested class is annotated with@TestInstance(Lifecycle.PER_CLASS).Step 2: Analyze the given code
The@BeforeAllmethod is non-static and the nested class is not annotated with@TestInstance, so this causes a runtime error.Final Answer:
@BeforeAll method must be static in nested classes -> Option CQuick Check:
@BeforeAll in nested must be static unless @TestInstance used [OK]
- Thinking @BeforeAll cannot be used in nested classes
- Forgetting static keyword on @BeforeAll method
- Confusing @BeforeAll with @BeforeEach
Solution
Step 1: Understand static requirement for @BeforeAll in nested classes
By default,@BeforeAllmethods in nested classes must be static because nested classes are instance classes.Step 2: Use @TestInstance(Lifecycle.PER_CLASS) to allow non-static @BeforeAll
Annotating the nested class with@TestInstance(Lifecycle.PER_CLASS)changes lifecycle so@BeforeAllcan be non-static, allowing setup without static nested class.Step 3: Evaluate other options
Make the nested class static and keep@BeforeAllmethod static requires static nested class, which is not desired. Use@BeforeEachinstead of@BeforeAllin nested class changes setup frequency. Move all tests to the outer class and remove nested classes removes nested structure, losing organization.Final Answer:
Annotate the nested class with @TestInstance(Lifecycle.PER_CLASS) and make the @BeforeAll method non-static -> Option DQuick Check:
@TestInstance(PER_CLASS) allows non-static @BeforeAll in nested [OK]
- Making nested class static when not needed
- Using @BeforeEach instead of @BeforeAll for once-only setup
- Removing nested classes to fix lifecycle issues
Ready to prove it?
Pass the test and this pattern moves unknown
