Java Top

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

More often than not, when writing unit tests, we'll encounter a situation where we need to mock a static method. Previous to version 3.4.0 of Mockito, it wasn't possible to mock static methods directly – only with the help of PowerMockito.

In this tutorial, we'll take a look at how we can now mock static methods using the latest version of Mockito. To learn more about testing with Mockito, check out our comprehensive Mockito series.

2. A Simple Static Utility Class

Throughout this tutorial, the focus of our tests will be a simple static utility class:

public class StaticUtils {

    private StaticUtils() {}

    public static List<Integer> range(int start, int end) {
        return IntStream.range(start, end)
          .boxed()
          .collect(Collectors.toList());
    }

    public static String name() {
        return "Baeldung";
    }
}

For demonstration purposes, we have one method with some arguments and another one that simply returns a String.

3. Dependencies

Let's get started by adding the mockito-inline dependency to our pom.xml:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-inline</artifactId>
    <version>3.8.0</version>
    <scope>test</scope>
</dependency>

It's worth noting that at some point, as per the documentation, this functionality may well be integrated into the more familiar mockito-core dependency.

4. A Quick Word on Testing Static Methods

Generally speaking, some might say that when writing clean object-orientated code, we shouldn't need to mock static classes. This could typically hint at a design issue or code smell in our application.

Firstly because a class depending on a static method has tight coupling, and secondly, it nearly always leads to code that is difficult to test. Ideally, a class should not be responsible for obtaining its dependencies, and if possible, they should be externally injected.

Therefore, it's always worth investigating if we can refactor our code to make it more testable. Of course, this is not always possible, and sometimes we're obliged to mock static methods.

5. Mocking a No Argument Static Method

Let's go ahead and see how we can mock the name method from our StaticUtils class:

@Test
void givenStaticMethodWithNoArgs_whenMocked_thenReturnsMockSuccessfully() {
    assertThat(StaticUtils.name()).isEqualTo("Baeldung");

    try (MockedStatic<StaticUtils> utilities = Mockito.mockStatic(StaticUtils.class)) {
        utilities.when(StaticUtils::name).thenReturn("Eugen");
        assertThat(StaticUtils.name()).isEqualTo("Eugen");
    }

    assertThat(StaticUtils.name()).isEqualTo("Baeldung");
}

As previously mentioned, since Mockito 3.4.0, we can use the Mockito.mockStatic(Class<T> classToMock) method to mock invocations to static method calls. This method returns a MockedStatic object for our type, which is a scoped mock object.

Therefore in our unit test above, the utilities variable represents a mock with a thread-local explicit scope. It's important to note that scoped mocks must be closed by the entity that activates the mock. This is why we define our mock within a try-with-resources construct so that the mock is closed automatically when we finish with our scoped block.

This is a particularly nice feature as it assures that our static mock remains temporary. As we know, if we're playing around with static method calls during our test runs, this will likely lead to adverse effects in our test results due to the concurrent and sequential nature of running tests.

On top of this, another nice side effect is that our tests will still run super fast as Mockito doesn't need to replace the classloader for every test.

In our example, we re-iterate this point by checking, before and after our scoped block, that our static method name returns a real value.

6. Mocking a Static Method With Arguments

Now, let's see another common use case when we need to mock a method that has arguments:

@Test
void givenStaticMethodWithArgs_whenMocked_thenReturnsMockSuccessfully() {
    assertThat(StaticUtils.range(2, 6)).containsExactly(2, 3, 4, 5);

    try (MockedStatic<StaticUtils> utilities = Mockito.mockStatic(StaticUtils.class)) {
        utilities.when(() -> StaticUtils.range(2, 6))
          .thenReturn(Arrays.asList(10, 11, 12));

        assertThat(StaticUtils.range(2, 6)).containsExactly(10, 11, 12);
    }

    assertThat(StaticUtils.range(2, 6)).containsExactly(2, 3, 4, 5);
}

As we can see, we follow the same approach as previously, except this time around, we use a lambda expression inside our when clause where we specify the method along with any arguments that we want to mock. Pretty straightforward!

7. Conclusion

In this quick article, we've seen a couple of examples of how we can use Mockito to mock static methods. In conclusion, Mockito provides a graceful solution using a narrower scope for mocked static objects via one small lambda.

As always, the full source code of the article is available over on GitHub.

Java bottom

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:

>> CHECK OUT THE COURSE
guest
0 Comments
Inline Feedbacks
View all comments