skip to content

Your code calls a static utility method that returns the current time, and you need it to return a fixed value inside one test. How do you stub that static call with Mockito, and how do you keep the stubbing from leaking outside the test?

level: middleimportance: must knowfreq 50%

answer

  1. try (MockedStatic<T> m = mockStatic(T.class))
  2. m.when(() -> T.call()).thenReturn(x)
  3. ALL statics of the class become mocked
  4. CALLS_REAL_METHODS keeps the rest real
  5. thread-local; needs inline mock maker

basics

~20 s

Open Mockito.mockStatic(TheClass.class) in a try-with-resources block; inside it, stub with mocked.when(TheClass::method).thenReturn(value). While the scope is open all static methods of that class are mocked on the current thread, and closing the scope restores the real implementations.

solid answer

~40 s

`Mockito.mockStatic(Clock.class)` returns a `MockedStatic<Clock>` — an `AutoCloseable` that, for the current thread, replaces the class's static methods with mock behaviour. Stubbing uses a lambda instead of a method call on an instance: ```java try (MockedStatic<Clock> clock = Mockito.mockStatic(Clock.class)) { clock.when(Clock::systemUTC).thenReturn(fixed); assertEquals(expected, service.stamp()); } ``` Two things surprise people. First, once the scope is open **every** static method of that class is mocked, not only the one you stub — unstubbed ones return null/0/false, so `mockStatic(type, CALLS_REAL_METHODS)` is the way to keep the rest real. Second, the registration is thread-local and scoped: only calls made on the test thread while the resource is open are affected, and try-with-resources is what unregisters it. It requires the inline mock maker, the default from Mockito 5.

code

java · 12 lines
java
@Test
void stampsFixedTime() {
    Instant fixed = Instant.parse("2026-01-01T00:00:00Z");

    try (MockedStatic<Instant> instants =
             Mockito.mockStatic(Instant.class, Mockito.CALLS_REAL_METHODS)) {
        instants.when(Instant::now).thenReturn(fixed);

        assertEquals(fixed, new AuditService().stamp().at());
        instants.verify(Instant::now);
    }
}

go deeper

for a junior

Recall the try-with-resources shape and the handle-based when(() -> ...) stubbing syntax.

for a middle

Explain that the whole static surface is mocked, know the CALLS_REAL_METHODS escape hatch, and know the scope is thread-local.

for a senior

Diagnose collateral damage from a wide scope, know the inline-mock-maker requirement, and prefer injected clocks or generators where the code is yours.

for a principal

Position static mocking as a boundary tool; argue for injectable time and ID abstractions so the technique is unnecessary in the domain layer.

## Why statics needed a special API Classic Mockito works by creating an object that stands in for a real one. A static method is not dispatched through an object at all — the call site is compiled to `invokestatic` on a named class — so no substitute instance can intercept it. Until Mockito 3.4.0 the answer was "wrap the static and mock the wrapper" or use a bytecode-rewriting framework. `Mockito.mockStatic` closed that gap by using the inline mock maker's Java agent to instrument the class's static methods in place. ## The shape of the API ```java try (MockedStatic<UUIDs> mocked = Mockito.mockStatic(UUIDs.class)) { mocked.when(UUIDs::next).thenReturn("fixed-id"); // exercise code that calls UUIDs.next() } ``` - `mockStatic(Class)` activates the mock and returns the control handle. - Stubbing goes through the handle: `mocked.when(Verification)`, where the `Verification` is a lambda that *performs* the static call. Mockito runs the lambda, records which static was invoked with which arguments, and binds the outcome. Argument matchers work inside the lambda: `mocked.when(() -> Files.readString(any()))`. - `mocked.verify(...)` checks static invocations, with the same verification modes as instance mocks. - `close()` removes the instrumentation. ## All statics of the class are affected This is the single most common surprise. Activating the scope turns the whole class's static surface into a mock: any static you did not stub returns the default answer for its type. Code that calls `StringUtils.isBlank(x)` elsewhere in the same path suddenly gets `false`, or a factory static returns `null` and the test fails far from the cause. Two mitigations: keep the scope as narrow as possible (open it around the exercise phase only), and use the overload `mockStatic(Type.class, Mockito.CALLS_REAL_METHODS)` so unstubbed statics run their real implementation while the ones you stub are overridden. ## Scoping and threads The registration is **thread-local**: only static calls executed on the thread that opened the scope see the mock. Production code that hops onto an executor, a reactive scheduler, or an `@Async` method calls the real static. This is deliberate — it lets tests run in parallel without stepping on each other — but it makes asynchronous code effectively untestable this way unless you force same-thread execution. The scope is also strictly bounded: state captured before it opened (a timestamp already stored in a field, a static initialiser that already ran) is unaffected. Mocking a static does not re-run or reset the class's static initialiser. ## Practical cases Typical legitimate uses are pinning time (`Instant.now()`, `LocalDate.now()`), pinning randomness (`UUID.randomUUID()`), and neutralising static helpers in third-party or legacy code. For your own code, taking a `Clock` or an ID generator as a dependency is cheaper and leaves no instrumentation in the test — the Java time API exposes `Clock.fixed(...)` precisely so that time can be injected. ## Requirements and limits It needs the inline mock maker (default from Mockito 5; the `mockito-inline` artifact on 3.4–4.x). Some JDK internals are excluded from instrumentation and cannot be mocked. Native and certain intrinsified methods are also off limits. And because the agent instruments the loaded class, the class must be loadable by the test's classloader in the ordinary way — exotic classloading setups can defeat it.

  • After opening the scope, an unrelated static helper on the same class starts returning null and the test fails oddly. Why?
    Activating a static mock replaces the entire static surface of that class, not just the method you stub. Everything unstubbed answers with the type's default — null, 0, false, empty. Fix it by stubbing the other statics too, by narrowing the scope so the other calls happen outside it, or by opening the mock with CALLS_REAL_METHODS so unstubbed statics keep their real behaviour.
  • Why does stubbing use a lambda, `mocked.when(() -> Foo.bar(x))`, rather than the familiar `when(Foo.bar(x))`?
    Mockito's classic `when` reads the last invocation recorded on a mock *instance*; a static call is not made on an instance, so there is nothing to read from. The handle-plus-lambda form makes the static call happen under Mockito's control, so it can record the target class, method and arguments. Argument matchers work normally inside the lambda.

saying these in an interview costs you the question

  • Believing only the stubbed static is affected while the rest of the class stays real.
  • Writing `when(Foo.bar())` instead of `mockedStatic.when(() -> Foo.bar())`.
  • Expecting statics called on a worker thread to be mocked.
  • Assuming it works without the inline mock maker on older Mockito versions.
  • Thinking the class's static initialiser is re-run or reset by the mock.

context