JUnit @Nested Annotation

JUnit is a popular testing framework in the Java ecosystem that simplifies writing and running tests. The @Nested annotation in JUnit 5 allows you to group related test classes inside a parent test class. This guide covers the basics of using the @Nested annotation to organize your tests hierarchically.

Table of Contents

  1. Introduction
  2. Steps to Use @Nested
  3. Real-World Use Case
  4. Conclusion

Introduction

The @Nested annotation allows you to group related test classes inside a parent test class. This helps in organizing tests logically and hierarchically, especially when dealing with complex test scenarios.

Steps to Use @Nested

Step 1: Add Maven Dependency

To use JUnit in your project, you need to add the JUnit dependency to your pom.xml file. Use the latest version of JUnit 5:

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.9.2</version>
    <scope>test</scope>
</dependency>

Step 2: Create the Class to be Tested

Create a Java class with methods that you want to test. For example, a simple Calculator class:

public class Calculator {
    public int add(int a, int b) {
        return a + b;
    }

    public int subtract(int a, int b) {
        return a - b;
    }

    public int multiply(int a, int b) {
        return a * b;
    }

    public int divide(int a, int b) {
        if (b == 0) {
            throw new IllegalArgumentException("Division by zero");
        }
        return a / b;
    }
}

Step 3: Create the Test Class with Nested Test Classes

Create a test class in the src/test/java directory. Use the @Nested annotation to group related test classes inside a parent test class.

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

@DisplayName("Calculator Test Suite")
public class CalculatorTest {
    private final Calculator calculator = new Calculator();

    @Nested
    @DisplayName("Addition Tests")
    class AdditionTests {
        @Test
        @DisplayName("Test Addition of Two Positive Numbers")
        void testAdditionOfTwoPositiveNumbers() {
            assertEquals(5, calculator.add(2, 3), "2 + 3 should equal 5");
        }

        @Test
        @DisplayName("Test Addition of Positive and Negative Number")
        void testAdditionOfPositiveAndNegativeNumber() {
            assertEquals(1, calculator.add(2, -1), "2 + (-1) should equal 1");
        }
    }

    @Nested
    @DisplayName("Subtraction Tests")
    class SubtractionTests {
        @Test
        @DisplayName("Test Subtraction of Two Positive Numbers")
        void testSubtractionOfTwoPositiveNumbers() {
            assertEquals(1, calculator.subtract(3, 2), "3 - 2 should equal 1");
        }

        @Test
        @DisplayName("Test Subtraction of Positive and Negative Number")
        void testSubtractionOfPositiveAndNegativeNumber() {
            assertEquals(3, calculator.subtract(2, -1), "2 - (-1) should equal 3");
        }
    }

    @Nested
    @DisplayName("Multiplication Tests")
    class MultiplicationTests {
        @Test
        @DisplayName("Test Multiplication of Two Positive Numbers")
        void testMultiplicationOfTwoPositiveNumbers() {
            assertEquals(6, calculator.multiply(2, 3), "2 * 3 should equal 6");
        }

        @Test
        @DisplayName("Test Multiplication of Positive and Negative Number")
        void testMultiplicationOfPositiveAndNegativeNumber() {
            assertEquals(-2, calculator.multiply(2, -1), "2 * (-1) should equal -2");
        }
    }

    @Nested
    @DisplayName("Division Tests")
    class DivisionTests {
        @Test
        @DisplayName("Test Division of Two Positive Numbers")
        void testDivisionOfTwoPositiveNumbers() {
            assertEquals(2, calculator.divide(6, 3), "6 / 3 should equal 2");
        }

        @Test
        @DisplayName("Test Division by Zero")
        void testDivisionByZero() {
            assertThrows(IllegalArgumentException.class, () -> calculator.divide(1, 0), "Division by zero should throw IllegalArgumentException");
        }
    }
}

In this example, the CalculatorTest class contains nested test classes for different operations (addition, subtraction, multiplication, and division). Each nested class groups related test methods, making the tests more organized and readable.

Step 4: Run the Test

You can run the test using your IDE, Maven, or Gradle.

Using an IDE:

Most IDEs, like IntelliJ IDEA and Eclipse, have built-in support for running JUnit tests. Simply right-click on your test class or method and select “Run.”

Using Maven:

If you’re using Maven, you can run your tests with the following command:

mvn test

Using Gradle:

If you’re using Gradle, you can run your tests with the following command:

gradle test

Real-World Use Case

In real-world applications, nested tests can help organize complex test scenarios. For example, a BankAccount class might have methods for deposits, withdrawals, and balance inquiries. Nested tests can be used to group these related test methods logically.

Create the Class to be Tested

Create a Java class that contains business logic. For example, a BankAccount class:

public class BankAccount {
    private double balance;

    public BankAccount(double initialBalance) {
        this.balance = initialBalance;
    }

    public double deposit(double amount) {
        if (amount > 0) {
            balance += amount;
        }
        return balance;
    }

    public double withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
        } else {
            throw new IllegalArgumentException("Invalid withdrawal amount");
        }
        return balance;
    }

    public double getBalance() {
        return balance;
    }
}

Create the Test Class with Nested Test Classes

Create a test class for the BankAccount in the src/test/java directory. Use the @Nested annotation to group related test classes inside a parent test class.

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

@DisplayName("Bank Account Test Suite")
public class BankAccountTest {
    private final BankAccount account = new BankAccount(100);

    @Nested
    @DisplayName("Deposit Tests")
    class DepositTests {
        @Test
        @DisplayName("Test Deposit of Positive Amount")
        void testDepositOfPositiveAmount() {
            assertEquals(150, account.deposit(50), "Depositing 50 should increase balance to 150");
        }

        @Test
        @DisplayName("Test Deposit of Negative Amount")
        void testDepositOfNegativeAmount() {
            assertEquals(100, account.deposit(-50), "Depositing -50 should not change balance");
        }
    }

    @Nested
    @DisplayName("Withdrawal Tests")
    class WithdrawalTests {
        @Test
        @DisplayName("Test Withdrawal of Valid Amount")
        void testWithdrawalOfValidAmount() {
            assertEquals(50, account.withdraw(50), "Withdrawing 50 should decrease balance to 50");
        }

        @Test
        @DisplayName("Test Withdrawal of Invalid Amount")
        void testWithdrawalOfInvalidAmount() {
            assertThrows(IllegalArgumentException.class, () -> account.withdraw(150), "Withdrawing 150 should throw IllegalArgumentException");
        }
    }

    @Nested
    @DisplayName("Balance Inquiry Tests")
    class BalanceInquiryTests {
        @Test
        @DisplayName("Test Balance Inquiry")
        void testBalanceInquiry() {
            assertEquals(100, account.getBalance(), "Balance should be 100");
        }
    }
}

In this example, the BankAccountTest class contains nested test classes for different operations (deposit, withdrawal, and balance inquiry). Each nested class groups related test methods, making the tests more organized and readable.

Running the Tests

You can run the tests using your IDE, Maven, or Gradle.

Using an IDE:

Most IDEs, like IntelliJ IDEA and Eclipse, have built-in support for running JUnit tests. Simply right-click on your test class or method and select “Run.”

Using Maven:

If you’re using Maven, you can run your tests with the following command:

mvn test

Using Gradle:

If you’re using Gradle, you can run your tests with the following command:

gradle test

Conclusion

The @Nested annotation in JUnit makes it easy to organize related test methods within a parent test class. By using @Nested, you can create a hierarchical structure for your tests, making them more readable and maintainable.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top