Using TestInstance lifecycle per class helps run all tests in the same object. This saves time and lets tests share data easily.
TestInstance lifecycle per class in JUnit
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class YourTestClass {
// test methods here
}This annotation tells JUnit to create one test class instance for all tests.
Default lifecycle is PER_METHOD, which creates a new instance for each test method.
@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class CalculatorTest { private Calculator calculator; @BeforeAll void setup() { calculator = new Calculator(); } @Test void testAdd() { assertEquals(5, calculator.add(2, 3)); } @Test void testSubtract() { assertEquals(1, calculator.subtract(3, 2)); } }
@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class CounterTest { private int counter = 0; @Test void testIncrement() { counter++; assertTrue(counter > 0); } @Test void testCounterValue() { assertEquals(1, counter); } }
This test class uses PER_CLASS lifecycle. The count variable is initialized once before all tests. Each test changes count, and the changes persist between tests.
import org.junit.jupiter.api.*; import static org.junit.jupiter.api.Assertions.*; @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class SampleTest { private int count = 0; @BeforeAll void init() { count = 10; System.out.println("BeforeAll: count = " + count); } @Test void testOne() { count++; System.out.println("TestOne: count = " + count); assertEquals(11, count); } @Test void testTwo() { count += 2; System.out.println("TestTwo: count = " + count); assertEquals(13, count); } }
Use PER_CLASS lifecycle only when tests can safely share state to avoid flaky tests.
@BeforeAll methods can be non-static with PER_CLASS lifecycle, unlike the default PER_METHOD.
Be careful with shared mutable state; reset if needed to keep tests independent.
PER_CLASS lifecycle creates one test instance for all tests in a class.
This allows sharing state and setup between tests easily.
It can improve performance and simplify setup but requires careful state management.
Practice
@TestInstance(TestInstance.Lifecycle.PER_CLASS) annotation do in a JUnit test class?Solution
Step 1: Understand the annotation purpose
The@TestInstance(TestInstance.Lifecycle.PER_CLASS)annotation tells JUnit to create only one instance of the test class for all test methods.Step 2: Compare with default behavior
By default, JUnit creates a new instance before each test method, but PER_CLASS changes this to reuse the same instance.Final Answer:
Creates a single test instance shared by all test methods in the class. -> Option AQuick Check:
PER_CLASS means one instance per class [OK]
- Confusing PER_CLASS with default PER_METHOD lifecycle
- Thinking PER_CLASS disables instance creation
- Assuming PER_CLASS runs tests in parallel
Solution
Step 1: Recall the full annotation syntax
The correct syntax uses the full enum path:@TestInstance(TestInstance.Lifecycle.PER_CLASS).Step 2: Check other options
@TestInstance(Lifecycle.PER_CLASS) misses theTestInstance.prefix, @TestInstance(PER_CLASS) is incomplete, and @TestInstance(Lifecycle.PER_METHOD) uses PER_METHOD which is default, not PER_CLASS.Final Answer:
@TestInstance(TestInstance.Lifecycle.PER_CLASS) -> Option AQuick Check:
Full enum path required in annotation [OK]
- Omitting TestInstance prefix in annotation
- Using PER_METHOD instead of PER_CLASS
- Using incorrect enum names or syntax
@TestInstance(TestInstance.Lifecycle.PER_CLASS):
import org.junit.jupiter.api.*;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class CounterTest {
private int count = 0;
@Test
void testIncrement() {
count++;
Assertions.assertEquals(1, count);
}
@Test
void testIncrementAgain() {
count++;
Assertions.assertEquals(2, count);
}
}
What will be the result when running these tests?Solution
Step 1: Understand PER_CLASS effect on instance
With PER_CLASS, the same test instance is used for both tests, so the fieldcountkeeps its value between tests.Step 2: Trace the count value changes
First test increments count from 0 to 1 and asserts 1. Second test increments count from 1 to 2 and asserts 2. Both assertions are correct.Final Answer:
Both tests pass because count is shared and increments correctly. -> Option DQuick Check:
Shared instance means shared state [OK]
- Assuming count resets before each test
- Expecting independent test instances
- Confusing PER_CLASS with PER_METHOD lifecycle
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class SampleTest {
private List<String> list = new ArrayList<>();
@BeforeEach
void setup() {
list.clear();
list.add("start");
}
@Test
void testOne() {
list.add("one");
Assertions.assertEquals(2, list.size());
}
@Test
void testTwo() {
list.add("two");
Assertions.assertEquals(2, list.size());
}
}
If the list.clear() call is removed from setup(), what problem will occur?Solution
Step 1: Analyze list state without clearing
Withoutlist.clear(), the list keeps accumulating elements from previous tests because the same instance is reused.Step 2: Understand assertion impact
Each test expects list size 2, but after first test, list size grows beyond 2, causing assertions to fail in subsequent tests.Final Answer:
Tests will fail because list keeps growing between tests. -> Option BQuick Check:
Shared state must be reset to avoid test interference [OK]
- Forgetting to reset mutable fields in PER_CLASS tests
- Assuming new instance per test with PER_CLASS
- Ignoring side effects between tests
@TestInstance(TestInstance.Lifecycle.PER_CLASS). Which of the following is the best practice to avoid flaky tests?Solution
Step 1: Understand shared state risks
With PER_CLASS lifecycle, the same instance is reused, so mutable fields keep their values across tests, risking interference.Step 2: Apply best practice for test isolation
Resetting mutable shared state in@BeforeEachensures each test starts fresh, preventing flaky or dependent tests.Final Answer:
Reset all mutable shared state in a@BeforeEachmethod. -> Option CQuick Check:
Reset shared state before each test to avoid flaky tests [OK]
- Relying only on constructor for setup with PER_CLASS
- Using static fields causing global state issues
- Ignoring test isolation principles
Ready to prove it?
Pass the test and this pattern moves unknown
