Mockito's Answers.RETURNS_MOCKS makes an unstubbed call return a fresh mock of its return type instead of null. Would you adopt that as the default for a whole test suite? Argue the tradeoffs.
answer
- unstubbed object return → fresh mock
- empty values first, then mock, else null
- no caching: two calls, two mocks
- vacuous green tests, lost NPE signal
- per-mock escape hatch, not global config
basics
~20 sRarely worth it suite-wide. It removes NPE noise but makes tests pass while exercising nothing real: every collaborator silently produces an object, so missing stubs and broken call chains stop failing. Prefer explicit stubbing plus strict stubs, and use it locally for wide legacy interfaces.
solid answer
~50 s`RETURNS_MOCKS` answers an unstubbed call by trying the ordinary empty-value defaults first, then returning a **new mock** of the return type if that type is mockable, else `null`. Each call produces a fresh mock, so the returned object is not remembered between calls. What it buys: tests against wide legacy interfaces stop dying on NPEs from values the test does not care about, and setup shrinks. What it costs: it converts "missing stub" from a loud failure into a silent success. Assertions on a value that flowed through a chain of auto-mocks pass vacuously; equality and `toString` comparisons behave oddly; and every unstubbed call allocates a mock, which is measurable in large suites. My position: keep the default `RETURNS_DEFAULTS`, add `Strictness.STRICT_STUBS`, and apply `RETURNS_MOCKS` per mock where a legacy type forces it — documented, never build-wide.
go deeper
Know the literal behaviour: unstubbed object returns come back as fresh mocks instead of null.
Add the mechanics — empty values first, new mock each call, null when unmockable — and one concrete downside.
Argue the tradeoff with failure-signal and semantics examples, and scope the setting to individual mocks.
Give a policy: default plus strict stubs, documented per-mock escape hatch, explicit rejection of global configuration, and an exit plan where it is used.
## What RETURNS_MOCKS actually does `Answers.RETURNS_MOCKS` is backed by `ReturnsMocks`. For an unstubbed invocation it first asks the ordinary `ReturnsEmptyValues` strategy — so primitives get `0`/`false`, collections get empties, `Optional` gets `empty()`. If that strategy has no opinion (i.e. the return type is a plain object type that would otherwise be `null`), it attempts to create a mock of the return type. If the type cannot be mocked, it returns `null`. Two details matter for the argument: - **it does not cache.** Two calls to the same unstubbed getter return two *different* mocks. So `assertSame(o.getA(), o.getA())` fails, and stubbing something on the object you got from one call has no effect on the next call's object. (Remembering the chain is a different feature with different semantics.) - **it is recursive in effect**: the mocks it creates carry the same default answer, so a whole graph of auto-mocks can materialise from one call. ## The case for suite-wide adoption The honest pro-argument: on wide, legacy, object-graph-heavy interfaces — think a domain façade with fifty getters returning other domain types — most of the objects a test touches are irrelevant to the behaviour under test, and stubbing them is pure ceremony. Auto-mocking removes hundreds of lines of setup and makes tests resilient to unrelated interface growth. Teams with a large surface of code they cannot restructure sometimes make this trade deliberately. ## The case against **It removes the failure signal.** With plain defaults, forgetting a stub eventually produces an NPE — ugly, but it *fails*. With auto-mocks, the code under test happily walks a graph of hollow objects, and the test passes while asserting almost nothing. That is the worst state for a test suite: green and uninformative. Vacuous passes accumulate silently and are only discovered when a production bug slips through a "covered" path. **It hides design pressure.** Long chains of collaborator calls are a Law-of-Demeter smell; the pain of stubbing them is feedback. Automating the pain away removes the incentive to introduce a narrower port or a value object. **Semantic surprises.** Auto-mocked values are non-null, so null-checks in production code take the other branch. `equals` is identity-based on mocks, so two calls never compare equal. `toString()` yields `Mock for X, hashCode: ...`, which pollutes assertion messages and logs. Numeric aggregation over auto-mocked values silently produces zeros. **Cost.** Every unstubbed object-returning call allocates a mock and registers it with the framework. Under the inline mock maker this includes instrumentation bookkeeping and retained invocation data, which shows up as memory growth in very large suites unless mocks are cleared. ## What I would do instead 1. **Default answer stays `RETURNS_DEFAULTS`.** Explicitness is the point of a unit test. 2. **Turn on `Strictness.STRICT_STUBS`** (the `MockitoExtension` default) so unused stubbings and argument mismatches fail. That attacks over-stubbing from the other side. 3. **For a specific painful legacy type, allow a targeted answer** — `RETURNS_MOCKS`, or a hand-written `Answer` that auto-mocks only a named subset of return types — created in the test that needs it, with a comment saying why. 4. **Prefer a fake or a builder** where the graph is really needed: `AdditionalAnswers.delegatesTo(fake)` gives realistic values instead of hollow ones, and test data builders give real objects you can assert on. 5. **Never set it through `IMockitoConfiguration`** for the whole build. That makes every mock in every module behave differently from what a reader of the Mockito docs expects, with no local evidence in the test file. ## How to frame it in an interview The principal-level answer is not "never use it". It is: name what the setting optimises for (setup brevity on wide interfaces), name what it trades away (failure signal, design feedback, deterministic semantics), state the blast radius of the global switch versus the per-mock switch, and land on a default with an explicit escape hatch. Being able to say *when you would* accept it — a legacy suite you must keep green while refactoring, with a plan to remove it — is what separates judgment from dogma.
- If you did adopt RETURNS_MOCKS on a specific mock, what would you add to keep the test honest?Assertions on concrete values rather than on objects that may be auto-mocked, plus explicit verification of the interactions that matter. Strict stubs stays on so the stubbings you do write must be used. A comment naming the legacy type and the reason keeps the next reader from copying the pattern into new code.
- Why does asserting equality between two values obtained from the same unstubbed getter fail under RETURNS_MOCKS?Because the answer creates a new mock on every unstubbed invocation rather than remembering the previous one. Mocks use identity equality unless equals is somehow handled, so the two instances are neither same nor equal. Any test that assumes a stable object identity from repeated calls will break.
- What is the operational cost of auto-mocking in a very large suite?Each unstubbed object-returning call allocates a mock and registers framework state for it, including recorded invocations and their arguments. Across tens of thousands of tests that is real time and heap, and under the inline mock maker the retained state is a known source of memory growth unless mocks are cleared between tests. The setting therefore has a runtime cost, not just a semantic one.
saying these in an interview costs you the question
- Claiming RETURNS_MOCKS caches and returns the same mock for repeated calls
- Presenting it as strictly safer than null with no downside
- Ignoring that it turns missing stubs into silently passing tests
- Recommending a build-wide IMockitoConfiguration change without discussing blast radius
- Assuming it can auto-mock any return type, including primitives and unmockable JDK types