How do you mock a static method with Mockito, and what does Mockito.mockStatic return?
answer
- mockStatic returns MockedStatic<T>
- when(lambda) not when(value) — no instance
- scoped: active until close()
- thread-local
- needs inline mock-maker
basics
~10 sCall Mockito.mockStatic(SomeClass.class). It returns a MockedStatic handle you use to stub the static methods. While that handle is open, real static calls are replaced by your stubs; closing it restores the real behavior.
solid answer
~30 sUse Mockito.mockStatic(SomeClass.class), which returns a MockedStatic<SomeClass> scope object. Inside that scope, call mocked.when(() -> SomeClass.someStatic()).thenReturn(value) to stub the static method, then exercise your code. You verify with mocked.verify(() -> SomeClass.someStatic()). The mock is active only while the MockedStatic is open and only on the current thread, so you must close it when done, normally with try-with-resources. Stubbing replaces the real static implementation for any caller on that thread; once closed, the real method runs again. This requires Mockito's inline mock-maker (the default since Mockito 5; opt-in before that). Frequent need to mock statics usually points at a design issue worth refactoring.
go deeper
Knows there is a special API, Mockito.mockStatic, and that you stub with when(() -> ...). May not know the scoping or mock-maker details.
Can write a working mockStatic test, stub and verify with lambdas, and knows it returns a MockedStatic handle that must be closed.
Explains the scope/lifetime, thread-local behavior, default-answer trap, and the inline mock-maker requirement; reaches for it sparingly.
Frames mockStatic as a last resort, steers teams toward injecting Clock/Supplier/seams instead, and weighs the bytecode-instrumentation cost and version policy.
## What is a static method? In Java, an **instance method** belongs to an object — you call `myList.size()`. A **static method** belongs to the class itself, not to any object: `Math.max(1, 2)`, `Instant.now()`, `UUID.randomUUID()`. You call it through the class name, and there is no object to substitute. ## Why mocking statics is hard Normal mocking works by **substitution**: a mock is a fake *object* that implements an interface or subclasses a class, and you pass it into the code under test in place of the real object (dependency injection). Static methods have no object to pass in — the call `UUID.randomUUID()` is hard-wired to the `UUID` class. So ordinary Mockito (`mock(...)`) cannot intercept it; there is nothing to inject. ## What Mockito.mockStatic does `Mockito.mockStatic(SomeClass.class)` installs a temporary interceptor on the **class** itself. It returns a handle of type `MockedStatic<SomeClass>`. While that handle is *open*, every call to a static method of `SomeClass` is routed to Mockito instead of the real implementation. You then: 1. **Stub** — tell it what to return: `mocked.when(() -> SomeClass.foo()).thenReturn("x");` 2. **Exercise** your code, which calls `SomeClass.foo()` and now gets `"x"`. 3. **Verify** (optional): `mocked.verify(() -> SomeClass.foo());` 4. **Close** the handle to remove the interceptor and restore the real method. The `when`/`verify` take a lambda (`Verification`/`MockedStatic.Verification`) rather than a value, because there is no instance to record the call on — the lambda *is* the call expression Mockito watches. ## Scope and lifetime The interceptor is **scoped**: it is active only between creation and `close()`. By default (and unstubbed) the static methods return Mockito's usual defaults (null, 0, empty collection), not the real result, unless you call `.thenCallRealMethod()` or `mockStatic(..., CALLS_REAL_METHODS)`. ## What you get back `MockedStatic<T>` is an `AutoCloseable`. That is the key to using it safely (see the try-with-resources question). It exposes `when(...)`, `verify(...)`, `reset()`, and `close()`. ## The inline mock-maker requirement Intercepting a *class's* static dispatch requires bytecode instrumentation — the **inline mock-maker** (backed by ByteBuddy + the JVM instrumentation API). This is the default in Mockito 5+; in Mockito 3/4 you had to opt in with the `mockito-inline` dependency or a `mockito-extensions/org.mockito.plugins.MockMaker` file. Without it, `mockStatic` throws. ## Design note Needing to mock statics is often a signal that the code reaches out to a hard dependency (clock, random, a static singleton) instead of receiving it via a parameter. Injecting a `Clock`/`Supplier`/interface usually removes the need entirely.
- Why does mocked.when() take a lambda instead of an expression like normal Mockito?There is no instance to record the invocation on, so you pass the static call wrapped in a lambda (a Verification functional interface). Mockito executes it under interception to identify which static method you mean.
- What happens to a static method you didn't explicitly stub while the MockedStatic is open?It returns Mockito's default answer (null/0/empty), not the real result, unless you created the mock with CALLS_REAL_METHODS or call thenCallRealMethod().
saying these in an interview costs you the question
- Thinking plain Mockito.mock() can stub a static call (no object to inject).
- Forgetting that unstubbed statics return Mockito defaults, not the real value.
- Believing the mock is global to the JVM rather than scoped to the handle and thread.