Bird
Raised Fist0
JUnittesting~20 mins

TestInstance lifecycle per class in JUnit - Practice Problems & Coding Challenges

Choose your learning style10 modes available
Challenge - 5 Problems
🎖️
JUnit PER_CLASS Mastery
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ Predict Output
intermediate
2:00remaining
JUnit TestInstance Lifecycle: Output of Counter Increment
Consider the following JUnit 5 test class using @TestInstance(Lifecycle.PER_CLASS). What will be the output when all tests run?
JUnit
import org.junit.jupiter.api.*;

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class CounterTest {
    private int counter = 0;

    @Test
    void testOne() {
        counter++;
        System.out.println("Counter in testOne: " + counter);
    }

    @Test
    void testTwo() {
        counter++;
        System.out.println("Counter in testTwo: " + counter);
    }

    @Test
    void testThree() {
        counter++;
        System.out.println("Counter in testThree: " + counter);
    }
}
ACounter in testOne: 1\nCounter in testTwo: 2\nCounter in testThree: 3
BCounter in testOne: 1\nCounter in testTwo: 1\nCounter in testThree: 1
CCounter in testOne: 0\nCounter in testTwo: 1\nCounter in testThree: 2
DCounter in testOne: 3\nCounter in testTwo: 3\nCounter in testThree: 3
Attempts:
2 left
💡 Hint
Remember that with PER_CLASS lifecycle, the same test instance is used for all tests.
❓ assertion
intermediate
2:00remaining
Correct Assertion for PER_CLASS Lifecycle Shared State
Given a JUnit 5 test class with @TestInstance(Lifecycle.PER_CLASS) and a shared list that tests add elements, which assertion correctly verifies the list size after two tests have run?
JUnit
import org.junit.jupiter.api.*;
import java.util.*;

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class ListTest {
    private List<String> items = new ArrayList<>();

    @Test
    void addFirst() {
        items.add("first");
    }

    @Test
    void addSecond() {
        items.add("second");
    }

    @Test
    void verifySize() {
        // Which assertion below correctly checks the list size?
    }
}
AAssertions.assertEquals(2, items.size());
BAssertions.assertEquals(1, items.size());
CAssertions.assertTrue(items.isEmpty());
DAssertions.assertNull(items);
Attempts:
2 left
💡 Hint
With PER_CLASS lifecycle, the list is shared and accumulates elements added in previous tests.
🔧 Debug
advanced
2:00remaining
Debugging Unexpected Test Behavior with PER_CLASS Lifecycle
A developer notices that tests in a JUnit 5 class annotated with @TestInstance(Lifecycle.PER_CLASS) fail intermittently due to shared mutable state. What is the most likely cause?
AStatic fields are reset before each test, causing loss of data.
BJUnit creates a new instance per test, so fields are always reset causing inconsistent state.
CThe @TestInstance annotation is ignored, so tests run in parallel causing race conditions.
DTests share the same instance, so mutable fields retain changes between tests causing interference.
Attempts:
2 left
💡 Hint
Think about how PER_CLASS lifecycle affects instance variables.
🧠 Conceptual
advanced
2:00remaining
Effect of PER_CLASS Lifecycle on @BeforeEach and @AfterEach
In a JUnit 5 test class annotated with @TestInstance(Lifecycle.PER_CLASS), how often are methods annotated with @BeforeEach and @AfterEach executed?
A@BeforeEach and @AfterEach run only once for the entire test class.
B@BeforeEach and @AfterEach run once per test method invocation, using the same test instance.
C@BeforeEach and @AfterEach run once per test instance creation, which is once per test method.
D@BeforeEach and @AfterEach do not run when using PER_CLASS lifecycle.
Attempts:
2 left
💡 Hint
Consider the difference between test instance lifecycle and lifecycle of setup/teardown methods.
❓ framework
expert
3:00remaining
Choosing TestInstance Lifecycle for Stateful Integration Tests
You are designing integration tests that require expensive setup and teardown, and tests must share state between methods. Which JUnit 5 TestInstance lifecycle is best and why?
APER_CLASS, because it runs each test in a separate thread for parallel execution.
BPER_METHOD, because it creates a new instance per test, ensuring complete isolation and no shared state.
CPER_CLASS, because it creates one instance for all tests, allowing shared state and reducing setup overhead.
DPER_METHOD, because it caches expensive setup between tests automatically.
Attempts:
2 left
💡 Hint
Think about instance reuse and shared state benefits.

Practice

(1/5)
1. What does the @TestInstance(TestInstance.Lifecycle.PER_CLASS) annotation do in a JUnit test class?
easy
A. Creates a single test instance shared by all test methods in the class.
B. Creates a new test instance before each test method runs.
C. Disables test instance creation for the class.
D. Runs tests in parallel threads automatically.

Solution

  1. 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.
  2. 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.
  3. Final Answer:

    Creates a single test instance shared by all test methods in the class. -> Option A
  4. Quick Check:

    PER_CLASS means one instance per class [OK]
Hint: PER_CLASS means one instance for all tests in class [OK]
Common Mistakes:
  • Confusing PER_CLASS with default PER_METHOD lifecycle
  • Thinking PER_CLASS disables instance creation
  • Assuming PER_CLASS runs tests in parallel
2. Which of the following is the correct syntax to set the test instance lifecycle to PER_CLASS in JUnit 5?
easy
A. @TestInstance(TestInstance.Lifecycle.PER_CLASS)
B. @TestInstance(Lifecycle.PER_CLASS)
C. @TestInstance(PER_CLASS)
D. @TestInstance(Lifecycle.PER_METHOD)

Solution

  1. Step 1: Recall the full annotation syntax

    The correct syntax uses the full enum path: @TestInstance(TestInstance.Lifecycle.PER_CLASS).
  2. Step 2: Check other options

    @TestInstance(Lifecycle.PER_CLASS) misses the TestInstance. prefix, @TestInstance(PER_CLASS) is incomplete, and @TestInstance(Lifecycle.PER_METHOD) uses PER_METHOD which is default, not PER_CLASS.
  3. Final Answer:

    @TestInstance(TestInstance.Lifecycle.PER_CLASS) -> Option A
  4. Quick Check:

    Full enum path required in annotation [OK]
Hint: Use full enum path: TestInstance.Lifecycle.PER_CLASS [OK]
Common Mistakes:
  • Omitting TestInstance prefix in annotation
  • Using PER_METHOD instead of PER_CLASS
  • Using incorrect enum names or syntax
3. Consider the following JUnit 5 test class with @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?
medium
A. Tests fail with NullPointerException.
B. Both tests fail because count resets to 0 before each test.
C. First test passes, second test fails due to count reset.
D. Both tests pass because count is shared and increments correctly.

Solution

  1. Step 1: Understand PER_CLASS effect on instance

    With PER_CLASS, the same test instance is used for both tests, so the field count keeps its value between tests.
  2. 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.
  3. Final Answer:

    Both tests pass because count is shared and increments correctly. -> Option D
  4. Quick Check:

    Shared instance means shared state [OK]
Hint: PER_CLASS shares instance; state persists across tests [OK]
Common Mistakes:
  • Assuming count resets before each test
  • Expecting independent test instances
  • Confusing PER_CLASS with PER_METHOD lifecycle
4. Given this test class using PER_CLASS 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?
medium
A. Tests will pass normally without issues.
B. Tests will fail because list keeps growing between tests.
C. Tests will throw NullPointerException.
D. JUnit will create new instances despite PER_CLASS.

Solution

  1. Step 1: Analyze list state without clearing

    Without list.clear(), the list keeps accumulating elements from previous tests because the same instance is reused.
  2. 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.
  3. Final Answer:

    Tests will fail because list keeps growing between tests. -> Option B
  4. Quick Check:

    Shared state must be reset to avoid test interference [OK]
Hint: Clear shared state in setup to avoid test interference [OK]
Common Mistakes:
  • Forgetting to reset mutable fields in PER_CLASS tests
  • Assuming new instance per test with PER_CLASS
  • Ignoring side effects between tests
5. You want to optimize a test class by sharing expensive setup across tests using @TestInstance(TestInstance.Lifecycle.PER_CLASS). Which of the following is the best practice to avoid flaky tests?
hard
A. Remove all assertions to speed up tests.
B. Avoid using @BeforeEach and rely on constructor initialization only.
C. Reset all mutable shared state in a @BeforeEach method.
D. Use static fields to hold shared state instead of instance fields.

Solution

  1. 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.
  2. Step 2: Apply best practice for test isolation

    Resetting mutable shared state in @BeforeEach ensures each test starts fresh, preventing flaky or dependent tests.
  3. Final Answer:

    Reset all mutable shared state in a @BeforeEach method. -> Option C
  4. Quick Check:

    Reset shared state before each test to avoid flaky tests [OK]
Hint: Always reset mutable state in @BeforeEach with PER_CLASS [OK]
Common Mistakes:
  • Relying only on constructor for setup with PER_CLASS
  • Using static fields causing global state issues
  • Ignoring test isolation principles
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard