Mockito Mocking Static Methods

Introduction

In this chapter, we will learn about mocking static methods using Mockito. Static methods are often used in utility classes and are not tied to a specific instance of a class. Mocking static methods allows you to isolate your tests from the actual static method implementations, making your tests more robust and easier to maintain.

What is Mocking Static Methods?

Mocking static methods involves creating a mock for methods that belong to a class rather than an instance of a class. This is useful for isolating tests from static methods that have side effects, such as those that interact with external systems or perform complex calculations.

Setting Up Mockito to Mock Static Methods

To mock static methods with Mockito, you need to use the mockito-inline library, which provides the necessary functionality. Ensure that you have the following dependencies in your pom.xml if you are using Maven:

<!-- https://mvnrepository.com/artifact/org.mockito/mockito-inline -->
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-inline</artifactId>
    <version>5.2.0</version>
    <scope>test</scope>
</dependency>
<!-- JUnit 5 dependency -->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.8.2</version>
    <scope>test</scope>
</dependency>

Example 1: DateUtils Class and BookingService Class

Utility Class with Static Methods

import java.time.LocalDate;

public class DateUtils {
    public static boolean isWeekend(LocalDate date) {
        return date.getDayOfWeek().getValue() >= 6;
    }

    public static LocalDate getCurrentDate() {
        return LocalDate.now();
    }
}

Service Class Using Static Methods

import java.time.LocalDate;

public class BookingService {
    public boolean isBookingAllowed() {
        LocalDate today = DateUtils.getCurrentDate();
        return !DateUtils.isWeekend(today);
    }
}

Test Class: BookingServiceTest

import static org.mockito.Mockito.*;
import static org.mockito.ArgumentMatchers.*;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import static org.junit.jupiter.api.Assertions.*;
import java.time.LocalDate;

public class BookingServiceTest {

    @Test
    void testIsBookingAllowed_MockStaticMethods() {
        try (MockedStatic<DateUtils> mockedStatic = mockStatic(DateUtils.class)) {
            // Mock the static method getCurrentDate to return a specific date
            mockedStatic.when(DateUtils::getCurrentDate).thenReturn(LocalDate.of(2023, 1, 1));
            // Mock the static method isWeekend to return true for the specific date
            mockedStatic.when(() -> DateUtils.isWeekend(LocalDate.of(2023, 1, 1))).thenReturn(true);

            // Create an instance of BookingService
            BookingService bookingService = new BookingService();

            // Call the method under test
            boolean result = bookingService.isBookingAllowed();

            // Assert the result
            assertFalse(result);

            // Verify that the static methods were called
            mockedStatic.verify(DateUtils::getCurrentDate);
            mockedStatic.verify(() -> DateUtils.isWeekend(LocalDate.of(2023, 1, 1)));
        }
    }
}

Explanation

  1. Creating Mocks:
    try (MockedStatic<DateUtils> mockedStatic = mockStatic(DateUtils.class)) {
    

    This line creates a mock object for the DateUtils class using a try-with-resources statement to ensure the mock is closed after use.

  2. Mocking Static Methods:
    mockedStatic.when(DateUtils::getCurrentDate).thenReturn(LocalDate.of(2023, 1, 1));
    mockedStatic.when(() -> DateUtils.isWeekend(LocalDate.of(2023, 1, 1))).thenReturn(true);
    

    These lines mock the getCurrentDate and isWeekend static methods to return January 1, 2023 and true respectively, regardless of the input arguments.

  3. Creating an Instance of BookingService:
    BookingService bookingService = new BookingService();
    

    This line creates an instance of the BookingService class.

  4. Calling the Method Under Test:
    boolean result = bookingService.isBookingAllowed();
    

    This line calls the isBookingAllowed method on the BookingService instance.

  5. Asserting the Result:
    assertFalse(result);
    

    This line asserts that the returned value is false.

  6. Verifying the Static Methods Were Called:
    mockedStatic.verify(DateUtils::getCurrentDate);
    mockedStatic.verify(() -> DateUtils.isWeekend(LocalDate.of(2023, 1, 1)));
    

    These lines verify that the getCurrentDate and isWeekend static methods were called with the specified arguments.

Output

Mockito Mocking Static Methods

Example 2: StringUtils Class and TextService Class

Utility Class with Static Methods

public class StringUtils {
    public static boolean isNullOrEmpty(String str) {
        return str == null || str.isEmpty();
    }

    public static String reverse(String str) {
        return new StringBuilder(str).reverse().toString();
    }
}

Service Class Using Static Methods

public class TextService {
    public String processText(String input) {
        if (StringUtils.isNullOrEmpty(input)) {
            return "Invalid input";
        }
        return StringUtils.reverse(input);
    }
}

Test Class: TextServiceTest

import static org.mockito.Mockito.*;
import static org.mockito.ArgumentMatchers.*;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import static org.junit.jupiter.api.Assertions.*;

public class TextServiceTest {

    @Test
    void testProcessText_MockStaticMethods() {
        try (MockedStatic<StringUtils> mockedStatic = mockStatic(StringUtils.class)) {
            // Mock the static method isNullOrEmpty to return true for empty string
            mockedStatic.when(() -> StringUtils.isNullOrEmpty(anyString())).thenReturn(true);
            // Mock the static method reverse to return the reversed string
            mockedStatic.when(() -> StringUtils.reverse(anyString())).thenAnswer(invocation -> {
                String str = invocation.getArgument(0);
                return new StringBuilder(str).reverse().toString();
            });

            // Create an instance of TextService
            TextService textService = new TextService();

            // Call the method under test with an empty string
            String result = textService.processText("");

            // Assert the result
            assertEquals("Invalid input", result);

            // Call the method under test with a non-empty string
            String result2 = textService.processText("hello");

            // Assert the result
            assertEquals("olleh", result2);

            // Verify that the static methods were called
            mockedStatic.verify(() -> StringUtils.isNullOrEmpty(""));
            mockedStatic.verify(() -> StringUtils.reverse("hello"));
        }
    }
}

Explanation

  1. Creating Mocks:
    try (MockedStatic<StringUtils> mockedStatic = mockStatic(StringUtils.class)) {
    

    This line creates a mock object for the StringUtils class using a try-with-resources statement to ensure the mock is closed after use.

  2. Mocking Static Methods:
    mockedStatic.when(() -> StringUtils.isNullOrEmpty(anyString())).thenReturn(true);
    mockedStatic.when(() -> StringUtils.reverse(anyString())).thenAnswer(invocation -> {
        String str = invocation.getArgument(0);
        return new StringBuilder(str).reverse().toString();
    });
    

    These lines mock the isNullOrEmpty and reverse static methods to return true for any string and the reversed string respectively, regardless of the input arguments.

  3. Creating an Instance of TextService:
    TextService textService = new TextService();
    

    This line creates an instance of the TextService class.

  4. Calling the Method Under Test with an Empty String:
    String result = textService.processText("");
    

    This line calls the processText method on the TextService instance with an empty string.

  5. Asserting the Result for Empty String:
    assertEquals("Invalid input", result);
    

    This line asserts that the returned value is Invalid input.

  6. Calling the Method Under Test with a Non-Empty String:
    String result2 = textService.processText("hello");
    

    This line calls the processText method on the TextService instance with the string “hello”.

  7. Asserting the Result for Non-Empty String:
    assertEquals("olleh", result2);
    

    This line asserts that the returned value is the reversed string “olleh”.

  8. Verifying the Static Methods Were Called:
    mockedStatic.verify(() -> StringUtils.isNullOrEmpty(""));
    mockedStatic.verify(() -> StringUtils.reverse("hello"));
    

    These lines verify that the isNullOrEmpty and reverse static methods were called with the specified arguments.

Conclusion

Mocking static methods using Mockito allows you to isolate your tests from the actual implementations of static methods.

By using the mockito-inline library, you can mock static methods and verify their interactions, making your tests more robust and maintainable. Understanding and utilizing static method mocking will help you write more effective and isolated unit tests. In this chapter, we covered two real-world examples: mocking static date utility methods and mocking static string utility methods. These examples demonstrate how to use Mockito to mock static methods and verify their behavior in different scenarios.

Leave a Comment

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

Scroll to Top