JUnit 5 Test Lifecycle | Java Fresher Interview
Fast recall
Quick revision
Core answer
Interview-ready guide
Interview answer
In a simple Jupiter class, @BeforeAll runs once before the test invocations. Under the default PER_METHOD lifecycle, Jupiter creates a new test instance for each method or parameterized invocation, runs @BeforeEach, runs the test, and then runs @AfterEach. After the invocations finish, @AfterAll runs once.
The fresh instance prevents ordinary instance fields from carrying values into the next test, which is why class-level hooks are normally static under PER_METHOD. It does not isolate static fields, a database, files, or other external state. With @TestInstance(PER_CLASS), one instance is reused and class-level hooks may be instance methods, so mutable fields need deliberate reset. Test method order is separate and should not be assumed from source order.
JUnit 5 Test Lifecycle | Java Fresher Interview
Direct Answer
For a simple Jupiter test class, @BeforeAll runs before its test invocations, then each invocation is surrounded by @BeforeEach and @AfterEach, and @AfterAll runs at the end. The default PER_METHOD lifecycle creates a new test instance for each test method or invocation. That isolates ordinary instance fields, but static fields, external systems, and other shared state can still couple tests.
Deep Dive & Architecture
JUnit begins the class lifecycle with @BeforeAll and ends it with @AfterAll. Between those hooks, every test invocation has its own cycle: JUnit creates the test instance under the default PER_METHOD mode, runs @BeforeEach, runs the test, and then runs @AfterEach.
For example, a class with two @Test methods runs the before-each and after-each hooks twice, but the before-all and after-all hooks once. The fresh instance prevents ordinary instance fields from leaking state between tests. Class-level lifecycle methods are therefore static by default. @TestInstance(PER_CLASS) permits non-static class-level hooks, but it also reuses one instance, so mutable fields must be reset deliberately. Test correctness must never depend on method order.
Code Example
class LifecycleTest {
@BeforeAll static void beforeAll() { System.out.println("beforeAll"); }
@BeforeEach void beforeEach() { System.out.println(" beforeEach"); }
@Test void testOne() { System.out.println(" testOne"); }
@Test void testTwo() { System.out.println(" testTwo"); }
@AfterEach void afterEach() { System.out.println(" afterEach"); }
@AfterAll static void afterAll() { System.out.println("afterAll"); }
}
// beforeAll appears first and afterAll last. Each test name is surrounded
// by beforeEach and afterEach. testOne and testTwo may run in either order
// unless a method orderer is configured.
Common Mistakes & Pitfalls
- Assuming one shared instance. Under the default lifecycle each test method or invocation gets a new instance; static fields and external systems can still carry state.
@BeforeAllbefore each test. It runs once for the container, not per invocation — that is@BeforeEach.- Non-static
@BeforeAllunderPER_METHOD. Jupiter rejects the lifecycle method unless it is static;PER_CLASSpermits an instance method. - Relying on source order. Test order is controlled only when an explicit orderer is configured, and ordinary tests should not depend on one another.
Check your understanding
Answer these without looking back at the article.
- What is @TestInstance(Lifecycle.PER_CLASS)?
- Can you guarantee test execution order in JUnit 5?
- How does @BeforeEach behave in @Nested test classes?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.