MockitoAnnotations.openMocks(this) returns an AutoCloseable. What does closing it do, what goes wrong in a large suite if you never close it, and how does it differ from the older initMocks call?
answer
- openMocks -> AutoCloseable -> close in @AfterEach
- inline mock maker keeps a process-wide registry
- unclosed = heap climbs across classes, late OOM
- initMocks returned void, deprecated in 3.4.0
- extension finishes its session for you
basics
~20 sClosing ends that mocking session and releases the mocks Mockito is holding. With the inline mock maker every mock is kept in a global registry until released, so never closing means mocks and everything they captured stay reachable across thousands of tests — growing memory, sometimes to OutOfMemoryError. initMocks returned nothing, which is why it was deprecated in favour of openMocks.
solid answer
~50 s`openMocks(this)` creates the annotated mocks and hands back an `AutoCloseable` representing that initialization. `close()` finishes it: mocks created by that call are detached from Mockito's internal state, which matters most under the **inline mock maker** (default since Mockito 5) because it keeps instrumented mocks in a global registry keyed by instance. Without a close, each test class leaves its mocks — and the stubbed answers, captured arguments and any objects those reference — reachable for the JVM's whole run. In a suite with thousands of tests in one fork, that shows up as steadily climbing heap and occasionally `OutOfMemoryError: Java heap space` or metaspace pressure. Store the closeable in a field, close it in `@AfterEach`, and let the failure propagate. `MockitoAnnotations.initMocks(this)` did the same initialization but returned `void`, so there was no handle to release; it was deprecated in Mockito 3.4.0. The JUnit 5 extension closes its session for you, which is one more reason to prefer it when you can.
code
java · 14 linesabstract class MockitoSupport {
private AutoCloseable mocks;
@BeforeEach
void openMockitoMocks() {
mocks = MockitoAnnotations.openMocks(this);
}
@AfterEach
void closeMockitoMocks() throws Exception {
mocks.close();
}
}go deeper
Know that openMocks returns something you should keep and close in the teardown method, and that the extension does it for you.
Explain that closing releases the mocks and finishes the session, and that initMocks was deprecated because it returned nothing to close.
Tie it to the inline mock maker's registry and the observable symptom — heap growth across a long single-fork suite ending in OOM — and describe how you would confirm it from a heap dump.
Make it structural: put initialization in one shared base class or standardize on the extension so the cleanup cannot be forgotten, and treat suite memory growth as a monitored property of CI rather than something to paper over with a bigger heap.
## What openMocks returns and why ```java private AutoCloseable mocks; @BeforeEach void init() { mocks = MockitoAnnotations.openMocks(this); } @AfterEach void release() throws Exception { mocks.close(); } ``` The returned `AutoCloseable` represents "the set of mocks this call created, plus the internal bookkeeping for them". Closing it tells Mockito that this batch is finished so the framework can drop its references and clear the associated state. That matters because of *how* Mockito holds mocks. ## The inline mock maker and the global registry Mockito has two mock makers. The classic **subclass** maker generates a subclass per mocked type; the mock object itself is an ordinary object, and once your test drops the reference the garbage collector reclaims it. The **inline** maker — the default since Mockito 5, and opt-in earlier via `mockito-inline` — instruments the original class's bytecode instead, so a method body must ask "is this receiver a registered mock?". Answering that requires a process-wide registry mapping mock instances to their handlers. Mockito uses weak references there, so mocks are not leaked forever in principle, but the practical picture in a long-lived test JVM is messier: strong references from a test class's fields, from captured argument lists, from stubbed answers holding whole object graphs, and from static state all conspire to keep entries alive. Closing the session explicitly clears Mockito's own hold immediately rather than hoping the collector gets around to it. The visible symptoms in a big suite that never closes: - heap usage that grows monotonically across test classes rather than sawtoothing; - an eventual `OutOfMemoryError: Java heap space` late in the run, often in an innocent test that merely happened to be last; - slow full GCs as the registry grows; - with heavy class mocking, metaspace growth from instrumented types. These are exactly the failures that look like flakiness and get "fixed" by raising the heap or forking more often, when the real cause is unclosed sessions. ## Beyond memory: session hygiene Closing also finishes the mocking session in the Mockito sense. Any state associated with the initialization is torn down cleanly, so one test's leftover partial interaction (an unfinished `when(...)`, for instance) is less likely to surface as a confusing failure inside the *next* test. Mockito's own recommendation is unambiguous: use `openMocks` and close it, or use the JUnit 5 extension, which opens and finishes a `MockitoSession` around each test automatically and therefore has nothing for you to forget. ## initMocks vs openMocks `MockitoAnnotations.initMocks(this)` is the historical API. It performs the same field initialization but returns `void`, so there is no way to release anything. Mockito 3.4.0 deprecated it and introduced `openMocks`, whose sole difference is the returned `AutoCloseable`. Seeing `initMocks` in a codebase is a reliable marker of test code that predates that release; the migration is mechanical — capture the return value and add an `@AfterEach` that closes it. ## Practical guidance - **Where to close:** `@AfterEach` for per-test initialization. Do not swallow the exception from `close()`; declare `throws Exception` on the teardown method. - **Try-with-resources** works if you initialize inside a single test method, but the field + `@AfterEach` pattern is what a class-wide setup needs. - **One place only:** put the init/close pair in a shared abstract base class rather than repeating it, so nobody forgets the close half. - **Prefer the extension** on JUnit 5 — it removes the failure mode entirely. - **Verify a suspicion cheaply:** run the suite in one fork with a modest heap and watch whether usage climbs across classes; if it does and adding `close()` flattens it, you have your answer. - **Not a substitute for `validateMockitoUsage()`**, which checks *usage correctness* after a test; closing is about *resource release*. The extension does both. ## Interview framing A good answer names the concrete mechanism — inline mock maker, process-wide registry, mocks and their captured graphs staying reachable — rather than a vague "it cleans up". Then connect it to the observable symptom (heap growth over a long single-fork suite, late OOM), state the `initMocks` deprecation, and finish with the pragmatic recommendation: on JUnit 5, let the extension own the session so this cannot be forgotten.
- A CI suite fails with OutOfMemoryError only when all modules run in a single JVM fork. How would you tell whether unclosed Mockito sessions are involved?Run the suite in one fork with a heap dump on OOM and inspect the dominator tree: a large retained set held by Mockito's inline mock-maker registry, or many live mock instances of types from already-finished test classes, points straight at unclosed sessions. Cross-check by grepping for `openMocks` without a matching `close()` and for the deprecated `initMocks`. Converting those classes to the JUnit 5 extension and re-measuring confirms it.
- Does the JUnit 5 Mockito extension need any explicit cleanup from you?No. The extension opens a `MockitoSession` before each test and finishes it afterwards, which both validates Mockito usage and releases the mocks, even when the test throws. That is one of the main reasons to prefer it over the manual call on Jupiter; the manual route only exists for cases where an extension cannot be registered.
Each openMocks call checks a set of tools out of a shared workshop. Closing returns them. Skip the return step in a thousand-test suite and the workshop floor is impassable long before anyone notices which team never tidied up.
saying these in an interview costs you the question
- Treating close() as optional cosmetics with no observable effect
- Still calling the deprecated initMocks and claiming it is equivalent
- Closing in @BeforeEach or never storing the returned handle
- Claiming the extension also requires a manual close
- Confusing close() with validateMockitoUsage(), which checks usage rather than releasing resources