Junit 5 @Nested

JUnit 5 test cases can be written inside a nested class as well. The nested class keeps the @Test case code and @Test result report much cleaner and organized. for this JUnit 5 provides us @Nested annotation.

JUnit 5 nested class test case provides 2 main benefits.

  • Now if required each test case can have its own pre and post test lifecycle.
  • All test case methods coexist together, hence we cannot have duplicate method names in 1 class, but because the nested class provides an additional namespace and is independent of the parent, it can have methods as the same name of the parent, but yes methods within the nested class must have unique names.

Make sure to add @Nested annotation on top of static class otherwise nested class test cases will not be considered.

package org.wesome.junit5;

public class AppleCalculator {
    public int addApple(int apple1, int apple2) {
        return apple1 + apple2;
    }

    public int subApple(int apple1, int apple2) {
        return apple1 - apple2;
    }
}
package org.wesome.junit5;

import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

class AppleCalculatorTest {
    @Test
    void addAppleTest() {
        System.out.println("AppleCalculatorTest.addAppleTest");
        AppleCalculator appleCalculator = new AppleCalculator();
        assertEquals(2, appleCalculator.addApple(1, 1), "1 apple + 1 apple is 2 apple");
    }

    @Test
    void subAppleTest() {
        System.out.println("AppleCalculatorTest.subAppleTest");
        AppleCalculator appleCalculator = new AppleCalculator();
        assertEquals(1, appleCalculator.subApple(2, 1), "2 apple - 1 apple is 1 apple");
    }

    @Nested
    class AddAppleInnerClass {
        @Test
        void addAppleTestCase1() {
            System.out.println("AddAppleInnerClass.addAppleTestCase1");
            AppleCalculator appleCalculator = new AppleCalculator();
            assertEquals(2, appleCalculator.addApple(1, 1), "1 apple + 1 apple is 2 apple");
        }

        @Test
        void addAppleTestCase2() {
            System.out.println("AddAppleInnerClass.addAppleTestCase2");
            AppleCalculator appleCalculator = new AppleCalculator();
            assertEquals(2, appleCalculator.addApple(1, 1), "1 apple + 1 apple is 2 apple");
        }
    }

    @Nested
    class SubAppleInnerClass {
        @Test
        void subAppleTestCase1() {
            System.out.println("SubAppleInnerClass.subAppleTestCase1");
            AppleCalculator appleCalculator = new AppleCalculator();
            assertEquals(1, appleCalculator.subApple(2, 1), "2 apple - 1 apple is 1 apple");
        }

        @Test
        void subAppleTestCase2() {
            System.out.println("SubAppleInnerClass.subAppleTestCase2");
            AppleCalculator appleCalculator = new AppleCalculator();
            assertEquals(1, appleCalculator.subApple(2, 1), "2 apple - 1 apple is 1 apple");
        }
    }
}
plugins {
    id 'java'
}

group 'org.wesome'
version '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

dependencies {
    testImplementation('org.junit.jupiter:junit-jupiter:5.6.2')
}
test {
    useJUnitPlatform()
}

Generated report will be much cleaner, seggrigated and easy to read.

There is no limit to the nested class, we can create as many nested classes as required.

package org.wesome.junit5;

public class AppleCalculator {
    public int addApple(int apple1, int apple2) {
        return apple1 + apple2;
    }

    public int subApple(int apple1, int apple2) {
        return apple1 - apple2;
    }
}
package org.wesome.junit5;

import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

class AppleCalculatorTest {
    @Test
    void addAppleTest() {
        System.out.println("AppleCalculatorTest.addAppleTest");
        AppleCalculator appleCalculator = new AppleCalculator();
        assertEquals(2, appleCalculator.addApple(1, 1), "1 apple + 1 apple is 2 apple");
    }

    @Test
    void subAppleTest() {
        System.out.println("AppleCalculatorTest.subAppleTest");
        AppleCalculator appleCalculator = new AppleCalculator();
        assertEquals(1, appleCalculator.subApple(2, 1), "2 apple - 1 apple is 1 apple");
    }

    @Nested
    class InnerClass1 {
        @Test
        void addAppleTest() {
            System.out.println("InnerClass1.addAppleTest");
            AppleCalculator appleCalculator = new AppleCalculator();
            assertEquals(2, appleCalculator.addApple(1, 1), "1 apple + 1 apple is 2 apple");
        }

        @Test
        void subAppleTest() {
            System.out.println("InnerClass1.subAppleTest");
            AppleCalculator appleCalculator = new AppleCalculator();
            assertEquals(1, appleCalculator.subApple(2, 1), "2 apple - 1 apple is 1 apple");
        }

    }

    @Nested
    class InnerClass2 {
        @Test
        void addAppleTest() {
            System.out.println("InnerClass2.addAppleTest");
            AppleCalculator appleCalculator = new AppleCalculator();
            assertEquals(2, appleCalculator.addApple(1, 1), "1 apple + 1 apple is 2 apple");
        }

        @Test
        void subAppleTest() {
            System.out.println("InnerClass2.subAppleTest");
            AppleCalculator appleCalculator = new AppleCalculator();
            assertEquals(1, appleCalculator.subApple(2, 1), "2 apple - 1 apple is 1 apple");
        }

    }
}
plugins {
    id 'java'
}

group 'org.wesome'
version '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

dependencies {
    testImplementation('org.junit.jupiter:junit-jupiter:5.6.2')
}
test {
    useJUnitPlatform()
}

We can create a multi-level nested class structure, ie a nested class inside another nested class.

package org.wesome.junit5;

public class AppleCalculator {
    public int addApple(int apple1, int apple2) {
        return apple1 + apple2;
    }

    public int subApple(int apple1, int apple2) {
        return apple1 - apple2;
    }
}
package org.wesome.junit5;

import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

class AppleCalculatorTest {
    @Test
    void addAppleTest() {
        System.out.println("AppleCalculatorTest.addAppleTest");
        AppleCalculator appleCalculator = new AppleCalculator();
        assertEquals(2, appleCalculator.addApple(1, 1), "1 apple + 1 apple is 2 apple");
    }

    @Test
    void subAppleTest() {
        System.out.println("AppleCalculatorTest.subAppleTest");
        AppleCalculator appleCalculator = new AppleCalculator();
        assertEquals(1, appleCalculator.subApple(2, 1), "2 apple - 1 apple is 1 apple");
    }

    @Nested
    class InnerClass1 {
        @Test
        void addAppleTest() {
            System.out.println("InnerClass1.addAppleTest");
            AppleCalculator appleCalculator = new AppleCalculator();
            assertEquals(2, appleCalculator.addApple(1, 1), "1 apple + 1 apple is 2 apple");
        }

        @Test
        void subAppleTest() {
            System.out.println("InnerClass1.subAppleTest");
            AppleCalculator appleCalculator = new AppleCalculator();
            assertEquals(1, appleCalculator.subApple(2, 1), "2 apple - 1 apple is 1 apple");
        }

        @Nested
        class InnerClass2 {
            @Test
            void addAppleTest() {
                System.out.println("InnerClass2.addAppleTest");
                AppleCalculator appleCalculator = new AppleCalculator();
                assertEquals(2, appleCalculator.addApple(1, 1), "1 apple + 1 apple is 2 apple");
            }

            @Test
            void subAppleTest() {
                System.out.println("InnerClass2.subAppleTest");
                AppleCalculator appleCalculator = new AppleCalculator();
                assertEquals(1, appleCalculator.subApple(2, 1), "2 apple - 1 apple is 1 apple");
            }

        }
    }
}
plugins {
    id 'java'
}

group 'org.wesome'
version '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

dependencies {
    testImplementation('org.junit.jupiter:junit-jupiter:5.6.2')
}

The life cycle method of the parent test case class will also be applicable for the tested class.

package org.wesome.junit5;

public class AppleCalculator {
    public int addApple(int apple1, int apple2) {
        return apple1 + apple2;
    }

    public int subApple(int apple1, int apple2) {
        return apple1 - apple2;
    }
}
package org.wesome.junit5;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

class AppleCalculatorTest {
    @AfterAll
    static void afterAll() {
        System.out.println("AppleCalculatorTest.afterAll");
    }

    @BeforeAll
    static void beforeAll() {
        System.out.println("AppleCalculatorTest.beforeAll");
    }

    @Test
    void addAppleTest() {
        System.out.println("AppleCalculatorTest.addAppleTest");
        AppleCalculator appleCalculator = new AppleCalculator();
        assertEquals(2, appleCalculator.addApple(1, 1), "1 apple + 1 apple is 2 apple");
    }

    @Test
    void subAppleTest() {
        System.out.println("AppleCalculatorTest.subAppleTest");
        AppleCalculator appleCalculator = new AppleCalculator();
        assertEquals(1, appleCalculator.subApple(2, 1), "2 apple - 1 apple is 1 apple");
    }

    @BeforeEach
    void setUp() {
        System.out.println("AppleCalculatorTest.setUp");
    }

    @AfterEach
    void tearDown() {
        System.out.println("AppleCalculatorTest.tearDown");
    }

    @Nested
    class InnerClass {

        @Test
        void addAppleTest() {
            System.out.println("InnerClass.addAppleTest");
            AppleCalculator appleCalculator = new AppleCalculator();
            assertEquals(2, appleCalculator.addApple(1, 1), "1 apple + 1 apple is 2 apple");
        }

        @Test
        void subAppleTest() {
            System.out.println("InnerClass.subAppleTest");
            AppleCalculator appleCalculator = new AppleCalculator();
            assertEquals(1, appleCalculator.subApple(2, 1), "2 apple - 1 apple is 1 apple");
        }
    }
}
plugins {
    id 'java'
}

group 'org.wesome'
version '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

dependencies {
    testImplementation('org.junit.jupiter:junit-jupiter:5.6.2')
}

If not mentioned then Junit 5 life cycle is PER_METHOD, a nested inner class can have all Junit 5 life cycle method except @BeforeAll and @AfterAll because the nested class cannot have static methods and both @BeforeAll and @AfterAll must be static.

package org.wesome.junit5;

public class AppleCalculator {
    public int addApple(int apple1, int apple2) {
        return apple1 + apple2;
    }

    public int subApple(int apple1, int apple2) {
        return apple1 - apple2;
    }
}
package org.wesome.junit5;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

class AppleCalculatorTest {
    @Test
    void addAppleTest() {
        System.out.println("AppleCalculatorTest.addAppleTest");
        AppleCalculator appleCalculator = new AppleCalculator();
        assertEquals(2, appleCalculator.addApple(1, 1), "1 apple + 1 apple is 2 apple");
    }

    @Test
    void subAppleTest() {
        System.out.println("AppleCalculatorTest.subAppleTest");
        AppleCalculator appleCalculator = new AppleCalculator();
        assertEquals(1, appleCalculator.subApple(2, 1), "2 apple - 1 apple is 1 apple");
    }

    @Nested
    class InnerClass {
        @BeforeAll
        void beforeAll() {
            System.out.println("InnerClass.beforeAll");
        }

        @AfterAll
        void afterAll() {
            System.out.println("InnerClass.afterAll");
        }

        @BeforeEach
        void setUp() {
            System.out.println("InnerClass.setUp");
        }

        @AfterEach
        void tearDown() {
            System.out.println("InnerClass.tearDown");
        }

        @Test
        void addAppleTest() {
            System.out.println("InnerClass1.addAppleTest");
            AppleCalculator appleCalculator = new AppleCalculator();
            assertEquals(2, appleCalculator.addApple(1, 1), "1 apple + 1 apple is 2 apple");
        }

        @Test
        void subAppleTest() {
            System.out.println("InnerClass1.subAppleTest");
            AppleCalculator appleCalculator = new AppleCalculator();
            assertEquals(1, appleCalculator.subApple(2, 1), "2 apple - 1 apple is 1 apple");
        }
    }
}
plugins {
    id 'java'
}

group 'org.wesome'
version '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

dependencies {
    testImplementation('org.junit.jupiter:junit-jupiter:5.6.2')
}

If we need to add @BeforeAll and @AfterAll then we have to change default life cycle from PER_METHOD to PER_CLASS.

package org.wesome.junit5;;

public class AppleCalculator {
    public int addApple(int apple1, int apple2) {
        return apple1 + apple2;
    }

    public int subApple(int apple1, int apple2) {
        return apple1 - apple2;
    }
}
package org.wesome.junit5;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;

import static org.junit.jupiter.api.Assertions.assertEquals;

class AppleCalculatorTest {
    @Test
    void addAppleTest() {
        System.out.println("AppleCalculatorTest.addAppleTest");
        AppleCalculator appleCalculator = new AppleCalculator();
        assertEquals(2, appleCalculator.addApple(1, 1), "1 apple + 1 apple is 2 apple");
    }

    @Test
    void subAppleTest() {
        System.out.println("AppleCalculatorTest.subAppleTest");
        AppleCalculator appleCalculator = new AppleCalculator();
        assertEquals(1, appleCalculator.subApple(2, 1), "2 apple - 1 apple is 1 apple");
    }

    @Nested
    @TestInstance(TestInstance.Lifecycle.PER_CLASS)
    class InnerClass {
        @BeforeAll
        void beforeAll() {
            System.out.println("InnerClass.beforeAll");
        }

        @AfterAll
        void afterAll() {
            System.out.println("InnerClass.afterAll");
        }

        @BeforeEach
        void setUp() {
            System.out.println("InnerClass.setUp");
        }

        @AfterEach
        void tearDown() {
            System.out.println("InnerClass.tearDown");
        }

        @Test
        void addAppleTest() {
            System.out.println("InnerClass1.addAppleTest");
            AppleCalculator appleCalculator = new AppleCalculator();
            assertEquals(2, appleCalculator.addApple(1, 1), "1 apple + 1 apple is 2 apple");
        }

        @Test
        void subAppleTest() {
            System.out.println("InnerClass1.subAppleTest");
            AppleCalculator appleCalculator = new AppleCalculator();
            assertEquals(1, appleCalculator.subApple(2, 1), "2 apple - 1 apple is 1 apple");
        }
    }
}
plugins {
    id 'java'
}

group 'org.example'
version '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

dependencies {
    testImplementation('org.junit.jupiter:junit-jupiter:5.6.2')
}

follow us on