There is a newer version available.
For the latest stable version, please use JUnit 6.0.1!

Nested Tests

@Nested tests give the test writer more capabilities to express the relationship among several groups of tests. Such nested tests make use of Java’s nested classes and facilitate hierarchical thinking about the test structure. Here’s an elaborate example, both as source code and as a screenshot of the execution within an IDE.

Nested test suite for testing a stack
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.EmptyStackException;
import java.util.Stack;

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

@DisplayName("A stack")
class TestingAStackDemo {

	@Test
	@DisplayName("is instantiated with new Stack()")
	void isInstantiatedWithNew() {
		new Stack<>();
	}

	@Nested
	@DisplayName("when new")
	class WhenNew {

		Stack<Object> stack;

		@BeforeEach
		void createNewStack() {
			stack = new Stack<>();
		}

		@Test
		@DisplayName("is empty")
		void isEmpty() {
			assertTrue(stack.isEmpty());
		}

		@Test
		@DisplayName("throws EmptyStackException when popped")
		void throwsExceptionWhenPopped() {
			assertThrows(EmptyStackException.class, stack::pop);
		}

		@Test
		@DisplayName("throws EmptyStackException when peeked")
		void throwsExceptionWhenPeeked() {
			assertThrows(EmptyStackException.class, stack::peek);
		}

		@Nested
		@DisplayName("after pushing an element")
		class AfterPushing {

			String anElement = "an element";

			@BeforeEach
			void pushAnElement() {
				stack.push(anElement);
			}

			@Test
			@DisplayName("it is no longer empty")
			void isNotEmpty() {
				assertFalse(stack.isEmpty());
			}

			@Test
			@DisplayName("returns the element when popped and is empty")
			void returnElementWhenPopped() {
				assertEquals(anElement, stack.pop());
				assertTrue(stack.isEmpty());
			}

			@Test
			@DisplayName("returns the element when peeked but remains not empty")
			void returnElementWhenPeeked() {
				assertEquals(anElement, stack.peek());
				assertFalse(stack.isEmpty());
			}
		}
	}
}

When executing this example in an IDE, the test execution tree in the GUI will look similar to the following image.

writing tests nested test ide
Executing a nested test in an IDE

In this example, preconditions from outer tests are used in inner tests by defining hierarchical lifecycle methods for the setup code. For example, createNewStack() is a @BeforeEach lifecycle method that is used in the test class in which it is defined and in all levels in the nesting tree below the class in which it is defined.

The fact that setup code from outer tests is run before inner tests are executed gives you the ability to run all tests independently. You can even run inner tests alone without running the outer tests, because the setup code from the outer tests is always executed.

Only non-static nested classes (i.e. inner classes) can serve as @Nested test classes. Nesting can be arbitrarily deep, and those inner classes are subject to full lifecycle support, including @BeforeAll and @AfterAll methods on each level.

Interoperability

@Nested may be combined with @ParameterizedClass in which case the nested test class is parameterized.

The following example illustrates how to combine @Nested with @ParameterizedClass and @ParameterizedTest.

@Execution(SAME_THREAD)
@ParameterizedClass
@ValueSource(strings = { "apple", "banana" })
class FruitTests {

	@Parameter
	String fruit;

	@Nested
	@ParameterizedClass
	@ValueSource(ints = { 23, 42 })
	class QuantityTests {

		@Parameter
		int quantity;

		@ParameterizedTest
		@ValueSource(strings = { "PT1H", "PT2H" })
		void test(Duration duration) {
			assertFruit(fruit);
			assertQuantity(quantity);
			assertFalse(duration.isNegative());
		}
	}
}

Executing the above test class yields the following output:

FruitTests ✔
├─ [1] fruit = "apple" ✔
│  └─ QuantityTests ✔
│     ├─ [1] quantity = 23 ✔
│     │  └─ test(Duration) ✔
│     │     ├─ [1] duration = "PT1H" ✔
│     │     └─ [2] duration = "PT2H" ✔
│     └─ [2] quantity = 42 ✔
│        └─ test(Duration) ✔
│           ├─ [1] duration = "PT1H" ✔
│           └─ [2] duration = "PT2H" ✔
└─ [2] fruit = "banana" ✔
   └─ QuantityTests ✔
      ├─ [1] quantity = 23 ✔
      │  └─ test(Duration) ✔
      │     ├─ [1] duration = "PT1H" ✔
      │     └─ [2] duration = "PT2H" ✔
      └─ [2] quantity = 42 ✔
         └─ test(Duration) ✔
            ├─ [1] duration = "PT1H" ✔
            └─ [2] duration = "PT2H" ✔