Mocking Static Fields and Singletons in Mockito

When writing unit tests, it is often necessary to mock certain dependencies to isolate the code under test. Mockito, a popular mocking framework for Java, provides various features to mock objects and behaviors. One of such features is the ability to mock static fields and singletons.

Why Mock Static Fields and Singletons?

Static fields and singletons can pose challenges when it comes to testing. They often represent global state or have complex initialization logic that is not suitable for unit tests. By mocking static fields and singletons, we can replace these dependencies with controlled mock objects, allowing us to test our code in isolation.

Mocking Static Fields

To mock a static field with Mockito, we can utilize the @MockedStatic annotation introduced in Mockito 3.4.0. This annotation allows us to mock all static methods and fields of a given class within the scope of a test method.

Here's an example:

import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import static org.mockito.Mockito.mockStatic;

public class StaticFieldTest {

    @Test
    public void testStaticFieldMocking() {
        try (MockedStatic<Config> mockedConfig = mockStatic(Config.class)) {
            mockedConfig.when(Config::getApiKey).thenReturn("mocked-api-key");

            // Perform your test

            mockedConfig.verify(Config::getApiKey);
        }
    }
}

In the above example, we use the @MockedStatic(Config.class) notation to create a mocked Config class. We then use the when() method to define the behavior of the mocked static field and the verify() method to verify that the field was accessed as expected.

Mocking Singletons

Mocking singletons can be done in a similar manner as mocking static fields. The difference lies in the approach of mocking the singleton instance rather than the static methods or fields. We can achieve this using Mockito's mock() method combined with the PowerMockito extension.

Consider the following example:

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.junit.jupiter.api.BeforeEach;
import static org.mockito.Mockito.when;
import org.powermock.modules.junit.jupiter.PowerMockExtension;

@ExtendWith(PowerMockExtension.class)
public class SingletonTest {

    @Mock
    private SingletonClass mockSingleton;

    @BeforeEach
    public void setup() {
        when(mockSingleton.getInstance()).thenReturn(mockSingleton);
    }

    @Test
    public void testSingletonMocking() {
        // Perform your tests using the mockSingleton instance
    }
}

In the above example, we use the @ExtendWith(PowerMockExtension.class) annotation to enable support for mocking static methods and classes with Mockito and PowerMockito. The @Mock annotation is used to create a mock instance of the singleton class, and the when() method defines the desired behavior for the getInstance() method.

Conclusion

When it comes to testing code that relies on static fields or singletons, Mockito provides powerful features to mock these dependencies. By using the @MockedStatic annotation or combining Mockito with PowerMockito, we can effectively replace static fields and singletons with mock objects, enabling us to write comprehensive and isolated unit tests.

Remember to use these features responsibly and sparingly. In general, it's a good practice to refactor code to reduce reliance on static fields and singletons, as they can introduce hidden dependencies and make testing more challenging.


noob to master © copyleft