0
0
JUnittesting~7 mins

Nested class lifecycle in JUnit

Choose your learning style9 modes available
Introduction

Nested class lifecycle helps organize tests in groups and control how often setup and cleanup happen for each group.

You want to group related tests inside a main test class.
You need separate setup for different groups of tests.
You want to run setup once per group instead of before every test.
You want clearer test reports showing test groups.
You want to avoid repeating setup code for similar tests.
Syntax
JUnit
import org.junit.jupiter.api.*;

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class OuterTest {

    @BeforeAll
    void beforeAllOuter() {
        // runs once before all tests in OuterTest
    }

    @Nested
    @TestInstance(TestInstance.Lifecycle.PER_CLASS)
    class InnerTest {

        @BeforeAll
        void beforeAllInner() {
            // runs once before all tests in InnerTest
        }

        @Test
        void testSomething() {
            // test code
        }
    }
}

Use @Nested to create a nested test class inside an outer test class.

Lifecycle annotations like @BeforeAll run once per class instance.

Examples
This example shows a nested class with setup before each test inside it.
JUnit
import org.junit.jupiter.api.*;

class OuterTest {

    @BeforeAll
    static void setupAll() {
        System.out.println("Setup once for all tests");
    }

    @Nested
    class GroupOne {

        @BeforeEach
        void setupEach() {
            System.out.println("Setup before each test in GroupOne");
        }

        @Test
        void testA() {
            System.out.println("Running testA");
        }
    }
}
Using @TestInstance(PER_CLASS) allows @BeforeAll to be non-static in nested classes.
JUnit
import org.junit.jupiter.api.*;

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class OuterTest {

    @Nested
    @TestInstance(TestInstance.Lifecycle.PER_CLASS)
    class InnerTest {

        @BeforeAll
        void init() {
            System.out.println("Init once for InnerTest");
        }

        @Test
        void testOne() {
            System.out.println("Test one running");
        }
    }
}
Sample Program

This test class has two nested groups: AdditionTests and SubtractionTests. Setup methods run at different times for each group. Assertions check correct math results.

JUnit
import org.junit.jupiter.api.*;

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class CalculatorTest {

    @BeforeAll
    void setupAll() {
        System.out.println("Setup for all tests");
    }

    @Nested
    @TestInstance(TestInstance.Lifecycle.PER_CLASS)
    class AdditionTests {

        @BeforeAll
        void setupAddition() {
            System.out.println("Setup for addition tests");
        }

        @Test
        void testAddPositive() {
            int result = 2 + 3;
            Assertions.assertEquals(5, result);
            System.out.println("testAddPositive passed");
        }

        @Test
        void testAddNegative() {
            int result = -1 + -1;
            Assertions.assertEquals(-2, result);
            System.out.println("testAddNegative passed");
        }
    }

    @Nested
    class SubtractionTests {

        @BeforeEach
        void setupSubtraction() {
            System.out.println("Setup before each subtraction test");
        }

        @Test
        void testSubtract() {
            int result = 5 - 3;
            Assertions.assertEquals(2, result);
            System.out.println("testSubtract passed");
        }
    }
}
OutputSuccess
Important Notes

Nested classes help keep tests organized and readable.

Use @TestInstance(TestInstance.Lifecycle.PER_CLASS) to allow non-static @BeforeAll in nested classes.

Setup in outer class runs before nested class setups.

Summary

Nested classes group related tests inside a main test class.

Lifecycle annotations control setup and cleanup timing per class or test.

Using nested lifecycle improves test organization and efficiency.