JUnit 5 @Nested Test Classes
Last Updated :
18 Oct, 2024
JUnit 5 introduced several powerful features to make testing in Java more flexible and expressive. One of these features is the @Nested
test classes, which allows for better organization of test cases by logically grouping them inside an outer test class. This can be particularly useful when dealing with complex scenarios or hierarchical structures that require the tests to be categorized and scoped in a clear and readable manner.
In this article, we will explore the @Nested
annotation in JUnit 5, discussing its signature, how it improves test organization, and how we can implement it effectively in our test suite. By the end, you will have a deep understanding of nested test classes and their applications.
Prerequisites:
- Basic understanding of Java programming.
- Familiarity with JUnit 5.
- Knowledge of Maven as a build dependency management system.
- JDK and IntelliJ IDEA installed in your system.
What is JUnit 5 @Nested Test Class?
The @Nested
annotation in JUnit 5 is used to declare inner test classes that are logically grouped within the outer test class. It provides an easy and readable way to organize related test cases under different categories. The @Nested
test class can access the outer class's instance variables and methods, sharing the same state and lifecycle as the outer test class.
Key Characteristics of @Nested Test Classes:
- Non-static inner classes: The test class annotated with
@Nested
must be non-static, meaning it has access to the outer class's fields and methods. - Logical grouping: It allows you to group related test cases based on different functionalities, use cases, or workflows.
- Test scope sharing: The
@Nested
class can share the outer class context and setup, making it easier to write tests with a shared state or resources. - Better readability: Test cases are naturally organized, resulting in a cleaner and more readable test suite.
Benefits of Using @Nested Test Classes
Here are some major benefits of using @Nested
test classes in unit tests:
- Improved Test Organization: Nested test classes allow you to categorize related test methods into separate groups, especially useful for larger classes with distinct functionalities.
- Shared Test Context: The nested test class has access to the outer test class’s variables and methods, eliminating the need to duplicate setup and teardown logic in every nested class.
- Reduced Boilerplate Code: By using the shared context, you can avoid redundant code.
- Test Clarity: Nested classes provide a clear structure, enhancing the readability and maintainability of the test code.
Implementation of @Nested Test Classes of JUnit
Let's create an example project using JUnit 5 @Nested
test classes, demonstrating how to organize tests using nested classes to handle different test scenarios.
Step 1: Create a New Maven Project
Create a new Maven project using IntelliJ IDEA. Choose the following options:
- Name: nested-tests-example
- Build System: Maven
Click on the Create button.
Project Structure
After project creation done successfully, the folder structure will look like the below image:
Step 2: Add JUnit 5 Dependencies to pom.xml
Open the pom.xml file and add the following dependencies for JUnit 5.
XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.gfg</groupId>
<artifactId>nested-tests-example</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- JUnit 5 API -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.9.0</version>
<scope>test</scope>
</dependency>
<!-- JUnit 5 Test Engine -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.9.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
</plugin>
</plugins>
</build>
</project>
Step 3: Create the Calculator Class
Create the Calculator class, which provides basic mathematical operations.
Calculator.java:
Java
package com.gfg;
public class Calculator {
// Adds two numbers
public int add(int a, int b)
{
return a + b;
}
// Subtracts one number from another
public int subtract(int a, int b)
{
return a - b;
}
// Multiplies two numbers
public int multiply(int a, int b)
{
return a * b;
}
// Divides one number by another; throws an exception when dividing by zero
public int divide(int a, int b)
{
if (b == 0)
{
throw new ArithmeticException("Cannot divide by zero");
}
return a / b;
}
}
Step 4: Main Class
This class demonstrates the usage of the Calculator
class.
Java
package com.gfg;
public class Main {
public static void main(String[] args) {
Calculator calculator = new Calculator();
// Example usage of Calculator methods
int additionResult = calculator.add(10, 5);
System.out.println("Addition (10 + 5): " + additionResult);
int subtractionResult = calculator.subtract(10, 5);
System.out.println("Subtraction (10 - 5): " + subtractionResult);
int multiplicationResult = calculator.multiply(10, 5);
System.out.println("Multiplication (10 * 5): " + multiplicationResult);
try {
int divisionResult = calculator.divide(10, 2);
System.out.println("Division (10 / 2): " + divisionResult);
} catch (ArithmeticException e) {
System.err.println("Error: " + e.getMessage());
}
}
}
Explanation:
- The
Main
class demonstrates how to use the Calculator
class methods for addition, subtraction, multiplication, and division. - It handles exceptions for division by zero.
Step 5: Create the CalculatorTest
Class (Unit Tests with @Nested)
Create the CalculatorTest
class and write the test cases using JUnit 5's @Nested
feature.
CalculatorTest.java:
Java
import com.gfg.Calculator;
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.*;
class CalculatorTest {
private Calculator calculator; // Instance of Calculator for testing
@BeforeEach
void setup() {
calculator = new Calculator(); // Initialize Calculator before each test
}
// Nested class for testing addition
@Nested
class AdditionTests {
@Test
void shouldReturnCorrectSumForTwoPositiveNumbers() {
assertEquals(5, calculator.add(2, 3)); // Test addition
}
@Test
void shouldReturnCorrectSumForPositiveAndNegativeNumber() {
assertEquals(2, calculator.add(5, -3)); // Test addition with negative number
}
@Test
void shouldReturnZeroWhenAddingZero() {
assertEquals(5, calculator.add(5, 0)); // Test addition with zero
}
}
// Nested class for testing subtraction
@Nested
class SubtractionTests {
@Test
void shouldReturnCorrectDifferenceForTwoPositiveNumbers() {
assertEquals(2, calculator.subtract(5, 3)); // Test subtraction
}
@Test
void shouldReturnCorrectDifferenceForPositiveAndNegativeNumber() {
assertEquals(8, calculator.subtract(5, -3)); // Test subtraction with negative number
}
@Test
void shouldReturnZeroWhenSubtractingSameNumbers() {
assertEquals(0, calculator.subtract(5, 5)); // Test subtraction of same numbers
}
}
// Nested class for testing multiplication
@Nested
class MultiplicationTests {
@Test
void shouldReturnCorrectProductForTwoPositiveNumbers() {
assertEquals(15, calculator.multiply(3, 5)); // Test multiplication
}
@Test
void shouldReturnZeroWhenMultiplyingWithZero() {
assertEquals(0, calculator.multiply(5, 0)); // Test multiplication with zero
}
@Test
void shouldReturnNegativeProductWhenOneNegativeNumber() {
assertEquals(-15, calculator.multiply(-3, 5)); // Test multiplication with negative number
}
}
// Nested class for testing division
@Nested
class DivisionTests {
@Test
void shouldReturnCorrectQuotientForTwoPositiveNumbers() {
assertEquals(2, calculator.divide(10, 5)); // Test division
}
@Test
void shouldThrowExceptionWhenDividingByZero() {
assertThrows(ArithmeticException.class, () -> calculator.divide(10, 0)); // Test division by zero
}
@Test
void shouldReturnNegativeQuotientWhenDividingWithNegativeNumber() {
assertEquals(-2, calculator.divide(-10, 5)); // Test division with negative number
}
}
}
- Class Setup: The
CalculatorTest
class uses @BeforeEach
to initialize a new Calculator
instance before each test. - Nested Classes:
- Each nested class (e.g.,
AdditionTests
, SubtractionTests
) groups related test cases, improving organization and readability. - Each test method is annotated with
@Test
, indicating that it is a test case.
Step 6: Run the Application
After the project completed, run the application, and it will show the below output:
Step 7: Running the Tests
To run the tests, execute the following Maven command in your terminal:
mvn test
Output:
This output confirms that all ten tests (across all nested classes) passed successfully.
Similar Reads
JUnit 5 - Eclipse Test Templates JUnit 5 simplifies the process of writing and executing test cases in Java applications. It offers enhanced support for modern Java features, increased extensibility, and a testing API that is more flexible and expressive. Test TemplatesA test template is a predefined format for writing test cases o
7 min read
JUnit 5 â @RepeatedTest JUnit 5 is a powerful and flexible testing framework in the Java ecosystem, widely used for unit testing Java applications. It introduces several modern features that simplify testing, making it a preferred choice for developers. One of its common features is the @RepeatedTest annotation, which is d
5 min read
JUnit 5 - Test Suites with Example JUnit 5 encourages a modular approach to test creation with its test suites. These suites function as containers, bundling multiple test classes for easier management and collective execution within a single run. In this article, we will learn about JUnit 5 - Test Suites. Test SuiteIn JUnit 5, a tes
2 min read
JUnit 5 - @ParameterizedTest Parameterized tests in JUnit 5 provide the ability to run the same test multiple times with different inputs, helping to improve code coverage and catch edge cases that might otherwise go unnoticed By automating test execution with multiple sets of input data, parameterized tests simplify validation
4 min read
JUnit 5 â Test Reports in HTML In this article, we will discuss how to view Test reports of JUnit 5 in HTML formats. By default, JUnit 5 produces test reports in the form of XML files but understanding XML files directly is not possible and we will need some other third-party tool to parse the XML and give us the information abou
4 min read