Spring Boot + PowerMock + JUnit 5 Example

Introduction

PowerMock is a Java framework that allows you to mock static methods, constructors, final classes, and more. This makes it a powerful tool for unit testing. Integrating PowerMock with JUnit 5 requires some additional configuration. In this tutorial, we will cover how to set up a Spring Boot 3 application and use PowerMock with JUnit 5 for testing.

Prerequisites

  1. Java Development Kit (JDK) 17 or later
  2. Apache Maven installed
  3. An IDE like IntelliJ IDEA or Eclipse

Step 1: Create a Spring Boot Project

You can create a Spring Boot project using Spring Initializr or your IDE.

Using Spring Initializr

  1. Go to Spring Initializr.
  2. Select the following options:
    • Project: Maven Project
    • Language: Java
    • Spring Boot: 3.0.0 or later
    • Group: com.example
    • Artifact: powermock-demo
    • Name: powermock-demo
    • Package name: com.example.powermockdemo
    • Packaging: Jar
    • Java: 17 or later
  3. Add the following dependencies:
    • Spring Web
    • Spring Boot Starter Test
  4. Click "Generate" to download the project zip file.
  5. Extract the zip file and open the project in your IDE.

Step 2: Add PowerMock Dependencies

Add the following dependencies to your pom.xml file:

<dependencies>
    <!-- Spring Boot Starter Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Spring Boot Starter Test -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <!-- PowerMock Dependencies -->
    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-module-junit4</artifactId>
        <version>2.0.9</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-api-mockito2</artifactId>
        <version>2.0.9</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-module-junit5</artifactId>
        <version>2.0.9</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <version>5.9.2</version>
        <scope>test</scope>
    </dependency>
</dependencies>

Step 3: Create a Simple Service

Create a new Java class named CalculationService in the com.example.powermockdemo package:

package com.example.powermockdemo;

public class CalculationService {

    public int calculateSum(int a, int b) {
        return a + b;
    }
}

Explanation: The CalculationService class contains a method calculateSum that returns the sum of two integers.

Step 4: Create a Static Utility Class

Create a new Java class named StaticUtility in the com.example.powermockdemo package:

package com.example.powermockdemo;

public class StaticUtility {

    public static int getConstantValue() {
        return 10;
    }
}

Explanation: The StaticUtility class contains a static method getConstantValue that returns a constant value.

Step 5: Create a Controller

Create a new Java class named CalculationController in the com.example.powermockdemo package:

package com.example.powermockdemo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CalculationController {

    @Autowired
    private CalculationService calculationService;

    @GetMapping("/calculate")
    public int calculateSum(@RequestParam int a, @RequestParam int b) {
        return calculationService.calculateSum(a, b);
    }

    @GetMapping("/constant")
    public int getConstantValue() {
        return StaticUtility.getConstantValue();
    }
}

Explanation: The CalculationController class has two endpoints: one for calculating the sum of two numbers and one for getting the constant value from the static utility class.

Step 6: Create PowerMock Test Class

Create a new test class named CalculationControllerTest in the src/test/java/com/example/powermockdemo package:

package com.example.powermockdemo;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit5.PowerMockExtension;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;

@ExtendWith(PowerMockExtension.class)
@PrepareForTest(StaticUtility.class)
public class CalculationControllerTest {

    @Mock
    private CalculationService calculationService;

    @InjectMocks
    private CalculationController calculationController;

    @BeforeEach
    public void setUp() {
        MockitoAnnotations.openMocks(this);
    }

    @Test
    public void testCalculateSum() {
        // Mocking the instance method
        when(calculationService.calculateSum(5, 3)).thenReturn(8);

        // Calling the controller method
        int result = calculationController.calculateSum(5, 3);

        // Asserting the result
        assertEquals(8, result);
    }

    @Test
    public void testGetConstantValue() {
        // Mocking the static method
        PowerMockito.mockStatic(StaticUtility.class);
        PowerMockito.when(StaticUtility.getConstantValue()).thenReturn(20);

        // Calling the controller method
        int result = calculationController.getConstantValue();

        // Asserting the result
        assertEquals(20, result);
    }
}

Explanation:

  • @ExtendWith(PowerMockExtension.class): Integrates PowerMock with JUnit 5.
  • @PrepareForTest(StaticUtility.class): Prepares StaticUtility for testing with PowerMock.
  • In testCalculateSum, we mock the instance method calculateSum using Mockito.
  • In testGetConstantValue, we mock the static method getConstantValue using PowerMock.

Step 7: Run the Tests

Run the tests using your IDE or by executing the following command in the terminal:

mvn test

You should see an output indicating that all tests have passed successfully.

Conclusion

In this tutorial, we demonstrated how to use PowerMock with JUnit 5 in a Spring Boot 3 application. We created a simple Spring Boot application, added PowerMock dependencies, and wrote tests to mock both instance and static methods. By following these steps, you can efficiently test your Spring Boot applications and ensure that even the most complex scenarios are properly tested. This approach allows you to mock static methods, constructors, and more, making your tests more robust and reliable.


Comments