Execution order of lifecycle methods in JUnit - Build an Automation Script
import org.junit.jupiter.api.*; import java.util.ArrayList; import java.util.List; import static org.junit.jupiter.api.Assertions.*; @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class LifecycleOrderTest { private final List<String> executionOrder = new ArrayList<>(); @BeforeAll void beforeAll() { executionOrder.add("BeforeAll"); } @BeforeEach void beforeEach() { executionOrder.add("BeforeEach"); } @Test void testOne() { executionOrder.add("TestOne"); } @Test void testTwo() { executionOrder.add("TestTwo"); } @AfterEach void afterEach() { executionOrder.add("AfterEach"); } @AfterAll void afterAll() { executionOrder.add("AfterAll"); // Now verify the order // Expected order: // BeforeAll // BeforeEach, TestOne, AfterEach // BeforeEach, TestTwo, AfterEach // AfterAll List<String> expectedOrder = List.of( "BeforeAll", "BeforeEach", "TestOne", "AfterEach", "BeforeEach", "TestTwo", "AfterEach", "AfterAll" ); assertEquals(expectedOrder, executionOrder, "Lifecycle methods did not execute in expected order"); } }
This test class uses JUnit 5 lifecycle annotations to track the order of method execution.
We use a list executionOrder to record each lifecycle method call.
@BeforeAll runs once before all tests, so it adds "BeforeAll" first.
@BeforeEach runs before each test method, so it adds "BeforeEach" before each test.
Each @Test method adds its own name to the list.
@AfterEach runs after each test method, adding "AfterEach".
@AfterAll runs once after all tests, adding "AfterAll" and then asserting the entire order matches the expected sequence.
We use @TestInstance(Lifecycle.PER_CLASS) to allow non-static @BeforeAll and @AfterAll methods for simplicity.
This approach confirms the lifecycle methods execute in the correct order by checking the list contents at the end.
Now add data-driven testing with 3 different test methods to verify lifecycle order for each
Practice
Solution
Step 1: Understand lifecycle annotations
@BeforeAll is designed to run once before all tests in the class.Step 2: Compare with other annotations
@BeforeEach runs before each test, @AfterEach after each test, and @AfterAll once after all tests.Final Answer:
@BeforeAll -> Option DQuick Check:
@BeforeAll runs once before all tests [OK]
- Confusing @BeforeEach with @BeforeAll
- Thinking @AfterAll runs before tests
- Mixing up @AfterEach and @BeforeEach
Solution
Step 1: Identify the annotation for after each test
@AfterEach is the annotation that runs a method after every test method.Step 2: Check method syntax
The method should be void and can have any name, here 'cleanup()' is valid.Final Answer:
@AfterEach void cleanup() {} -> Option AQuick Check:
@AfterEach runs after each test method [OK]
- Using @AfterAll instead of @AfterEach
- Confusing @BeforeEach with @AfterEach
- Missing void return type
@BeforeAll
static void initAll() { System.out.println("InitAll"); }
@BeforeEach
void init() { System.out.println("Init"); }
@Test
void testOne() { System.out.println("TestOne"); }
@Test
void testTwo() { System.out.println("TestTwo"); }
@AfterEach
void tearDown() { System.out.println("TearDown"); }
@AfterAll
static void tearDownAll() { System.out.println("TearDownAll"); }What is the correct order of printed lines when running this test class?
Solution
Step 1: Understand lifecycle method order
@BeforeAll runs once before all tests, then for each test @BeforeEach runs, test runs, then @AfterEach runs. Finally, @AfterAll runs once after all tests.Step 2: Apply to given methods
Output order: InitAll (once), then for testOne: Init, TestOne, TearDown; for testTwo: Init, TestTwo, TearDown; finally TearDownAll.Final Answer:
InitAll, Init, TestOne, TearDown, Init, TestTwo, TearDown, TearDownAll -> Option AQuick Check:
BeforeAll once, BeforeEach-Test-AfterEach per test, AfterAll once [OK]
- Mixing order of BeforeAll and BeforeEach
- Forgetting AfterEach runs after each test
- Placing AfterAll before AfterEach
@BeforeAll
void setupAll() { System.out.println("Setup all"); }
@Test
void testMethod() { System.out.println("Test"); }What is the problem with this code?
Solution
Step 1: Recall @BeforeAll requirements
In JUnit 5, @BeforeAll methods must be static unless using a test instance lifecycle that allows non-static.Step 2: Check method signature
The method 'setupAll' is not static, which causes a runtime error or test failure.Final Answer:
@BeforeAll method must be static. -> Option BQuick Check:
@BeforeAll requires static method by default [OK]
- Making @BeforeAll non-static without lifecycle config
- Assuming @BeforeAll can be private
- Thinking @BeforeAll must return a value
Solution
Step 1: Assign tasks to lifecycle methods
Opening and closing the database connection should happen once, so use @BeforeAll and @AfterAll.Step 2: Use per-test methods for data reset and cleanup
Resetting data and cleaning up should happen before and after each test, so use @BeforeEach and @AfterEach.Final Answer:
@BeforeAll for opening connection, @AfterAll for closing connection, @BeforeEach for resetting data, @AfterEach for cleanup -> Option CQuick Check:
Once methods for setup/teardown, each methods for per-test tasks [OK]
- Opening connection before each test unnecessarily
- Resetting data only once before all tests
- Closing connection after each test causing overhead
Ready to prove it?
Pass the test and this pattern moves unknown
