How to mock static methods with Mockito

May 01, 2022 2 Comments Mockito Library Mock Static

1. Introduction

This article will be covering mocking static methods with Mockito. We will try to answer the question is this even possible to do it and why should we ever mock anything that is static.

2. Static methods

Let's start with a simple definition. Static methods are that methods in Java that can be called without creating an instance of the class. A static method belongs to the class rather than the object of a class.

Using static methods in Java is sometimes necessary, however, most developers limit their use to pure functions which are independent (not using external dependencies). Whether we like them or not, we do sometimes have to rely on them and also mock them in unit tests.

3. Mocking static method with Mockito 3.x

The good news is that from the latest Mockito version mocking static methods is finally supported.

To make this possible, a single dependency had to be added to the pom.xml file:

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

The latest version of Mockito inline dependency should be found in our Maven Repository.

If you are using mockito-core you will need to replace it with mockito-inline dependency otherwise you will face the following exception:

org.mockito.exceptions.base.MockitoException: 
The used MockMaker SubclassByteBuddyMockMaker does not support the creation of static mocks

Mockito's inline mock maker supports static mocks based on the Instrumentation API.
You can simply enable this mock mode, by placing the 'mockito-inline' artifact where you are currently using 'mockito-core'.
Note that Mockito's inline mock maker is not supported on Android.

3.1. Simple class with a static method use for testing

Let's consider we have a simple class WelcomeUtil with a single static method generateWelcome(...) that we want to mock in the JUnit test:

package com.frontbackend.libraries.mockito;

public final class WelcomeUtil {

    public static String generateWelcome(String name) {
        return String.format("Welcome %s", name);
    }

    private WelcomeUtil() {
    }
}

3.2. Mockito test class

The test code of this class could looks as follows:

package com.frontbackend.libraries.mockito;

import static org.junit.Assert.assertEquals;

import org.junit.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;

public class MockitoStaticMethodTest {

    @Test
    public void testMockStaticMethods() {
        assertEquals("Welcome John", WelcomeUtil.generateWelcome("John"));

        try (MockedStatic<WelcomeUtil> theMock = Mockito.mockStatic(WelcomeUtil.class)) {
            theMock.when(() -> WelcomeUtil.generateWelcome("John"))
                   .thenReturn("Guten Tag John");

            assertEquals("Guten Tag John", WelcomeUtil.generateWelcome("John"));
        }

        assertEquals("Welcome John", WelcomeUtil.generateWelcome("John"));
    }
}

There are some things we need to explain here:

  • note that mocked static method will be only visible in the try-with-resources block,
  • so different test cases should be tested in different try blocks,
  • static methods could be mocked only using an inline way,
  • after try-with-resource block behavior of the static method will be as originally implemented.

4. Mocking static method with Mockito in older versions 2.x

Now, what about the older version of the Mockito framework? does it support mocking static methods?. The answer is unfortunately NO.

But we could use another library such as PowerMock to mock the static method without using the latest version of Mockito.

First, let's start with adding necessary dependencies to our pom.xml file:

<?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">
    <parent>
        <artifactId>libraries</artifactId>
        <groupId>com.frontbackend.libraries</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>powermock</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
            <version>2.23.4</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-core</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-junit4</artifactId>
            <version>2.0.9</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

The list of dependencies we used (you can check the latest versions in links below):

4.1. PowerMock test class

The PowerMock uses internally Mockito API so we still need the Mockito library in our dependencies.

The following shows how to create a test that mocks the static WelcomeUtil.generateWelcome(...) method just like in the above example:

package com.frontbackend.libraries.powermock;

import static org.junit.Assert.assertEquals;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.when;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import com.frontbackend.libraries.powermock.utils.WelcomeUtil;

@RunWith(PowerMockRunner.class)
@PrepareForTest(WelcomeUtil.class)
public class PowermockStaticMethodTest {

    @Test
    public void shouldMockStaticMethodTest() {
        final String value = "Guten Tag John";

        mockStatic(WelcomeUtil.class);

        when(WelcomeUtil.generateWelcome("John")).thenReturn(value);

        assertEquals("Guten Tag John", WelcomeUtil.generateWelcome("John"));
    }
}

In this example mockStatic(...) and when(...) methods comes from PowerMockito library.

5. Mocking static method with Mockito 4.x

What about Mockito in version 4.x? The same as for 3.x, you will still need the mockito-inline library to mock static methods otherwise the system will throw a MockitoException. The good news is that we don't have to declare mockito-core separately because mockito-inline uses mockito-core as dependency.

<?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">
    <parent>
        <artifactId>libraries</artifactId>
        <groupId>com.frontbackend.libraries</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>mockito-static-v4</artifactId>

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

</project>

6. Conclusion

In this article, we presented how to mock static methods with Mockito and PowerMockito libraries. When it is not about mocking methods from third-party libraries, consider refactoring the code so that mocking a static method wouldn't be necessary. It is always not the best solution.

Test examples used in this article, are available in the GitHub Repository:

{{ message }}

{{ 'Comments are closed.' | trans }}