Mocking Static Methods with Mockito

Illustration for Mocking Static Methods with Mockito
By Last updated:

Static methods have long been considered a challenge in unit testing because they are tightly coupled and hard to replace. However, with the evolution of Mockito (version 3.4.0 and above), developers can now mock static methods directly, making it easier to test legacy and utility-heavy codebases.


Why Mock Static Methods?

  • Legacy Code: Many old Java projects use static utility methods extensively.
  • Isolate Dependencies: Prevent actual static calls (like UUID.randomUUID()) from interfering with tests.
  • Improve Reliability: Ensure tests focus on logic instead of external or non-deterministic behaviors.
  • Enable CI/CD Stability: Prevent flaky builds caused by time, randomness, or static resource usage.

Analogy: Mocking static methods is like replacing a factory’s conveyor belt temporarily to check if downstream processes work as expected, without actually running the heavy machinery.


Example: Basic Static Method Mocking

Utility Class

class Utils {
    static String getGreeting() {
        return "Hello, World!";
    }
}

Service Class

class GreetingService {
    String greet() {
        return Utils.getGreeting();
    }
}

Test with Static Mock

@ExtendWith(MockitoExtension.class)
class GreetingServiceTest {

    @Test
    void shouldMockStaticMethod() {
        try (MockedStatic<Utils> mockedStatic = Mockito.mockStatic(Utils.class)) {
            mockedStatic.when(Utils::getGreeting).thenReturn("Mocked Hello");

            GreetingService service = new GreetingService();
            assertEquals("Mocked Hello", service.greet());
        }
    }
}

Here, we replace the behavior of Utils.getGreeting() with "Mocked Hello" for the duration of the test.


Verifying Static Calls

Mockito also allows verifying that a static method was invoked:

@Test
void shouldVerifyStaticCall() {
    try (MockedStatic<Utils> mockedStatic = Mockito.mockStatic(Utils.class)) {
        GreetingService service = new GreetingService();
        service.greet();

        mockedStatic.verify(Utils::getGreeting);
    }
}

This ensures the static method is called as expected.


Advanced Example: Mocking Static Random Generators

class IdGenerator {
    static String generateId() {
        return UUID.randomUUID().toString();
    }
}
@Test
void shouldMockRandomIdGenerator() {
    try (MockedStatic<UUID> mockedUUID = Mockito.mockStatic(UUID.class)) {
        UUID fakeUuid = UUID.fromString("123e4567-e89b-12d3-a456-426614174000");
        mockedUUID.when(UUID::randomUUID).thenReturn(fakeUuid);

        assertEquals("123e4567-e89b-12d3-a456-426614174000", IdGenerator.generateId());
    }
}

This makes random generation deterministic for tests.


Best Practices

  1. Limit Usage: Don’t overuse static mocking; prefer dependency injection for cleaner design.
  2. Use try-with-resources: Ensures mocks are reverted after use.
  3. Target Legacy Code: Focus static mocking on legacy utilities and third-party libraries.
  4. Combine with Verifications: Verify static calls when ensuring correct interactions.
  5. Isolate Tests: Each test should independently mock static methods as needed.

Version Tracker

  • Mockito 3.4.0: Introduced static mocking support.
  • Mockito 4.x: Improved integration with JUnit 5.
  • Mockito with Inline Mocking Plugin: Required for static mocking (mockito-inline dependency).

Integration with CI/CD Pipelines

Static mocking ensures flaky behaviors like System.currentTimeMillis() or UUID.randomUUID() don’t break builds. Combined with Testcontainers for integration testing, it allows teams to validate both isolated and real-world scenarios effectively.


Conclusion & Key Takeaways

Mockito’s ability to mock static methods is a game-changer for testing legacy Java applications.

Key Takeaways:

  • Use MockedStatic for mocking static methods.
  • Always use try-with-resources for cleanup.
  • Best suited for legacy or utility code.
  • Prefer dependency injection for new designs.

FAQ

1. Can Mockito mock static methods?
Yes, since version 3.4.0 with the mockito-inline dependency.

2. Do I need special setup for static mocking?
Yes, add mockito-inline to your dependencies.

3. Can I mock multiple static methods at once?
Yes, but be cautious about readability.

4. Is static mocking thread-safe?
Generally, yes, but keep mocks scoped with try-with-resources.

5. Should I prefer mocking static methods or refactoring?
Prefer refactoring, but static mocking is ideal for legacy code.

6. How do I verify static method calls?
Use mockedStatic.verify().

7. Can I mock private static methods?
Not directly with Mockito; consider refactoring.

8. Does mocking static methods affect other tests?
No, if you scope mocks properly with try-with-resources.

9. What is a common pitfall?
Forgetting to include mockito-inline dependency.

10. Can I use static mocking with JUnit 5?
Yes, Mockito fully supports JUnit 5.