When and how do you use thenAnswer (and the related thenReturn vs thenAnswer distinction) to produce dynamic mock responses based on the call's arguments?
answer
- thenReturn = eager, once, fixed value
- thenAnswer(inv -> ...) = runs per call, sees arguments
- inv.getArgument(i) reads actual args
- returnsFirstArg() for save(e) -> e
- doAnswer().when() for void methods
basics
~20 sthenReturn gives a fixed value computed once. thenAnswer runs your code on every call, so you can build the return value from the actual arguments — useful when the answer depends on what was passed in.
solid answer
~50 sthenReturn evaluates its value eagerly, once, at stubbing time, and returns that same object on every call. thenAnswer instead takes an Answer<T> callback that Mockito invokes on every matching call, passing an InvocationOnMock from which you read the real arguments via invocation.getArgument(i). Use thenAnswer when the response must depend on the inputs — e.g. echo the saved entity back with an assigned id, compute a value, or return different things based on an argument. It's also how you lazily defer expensive value creation. Common idioms: returning the first argument (AdditionalAnswers.returnsFirstArg(), handy for repository.save(e) -> e), or capturing arguments. Caveats: a thenAnswer block runs real code each call, so keep it side-effect-light and deterministic; overusing it to encode complex logic is a smell that the collaborator should be a real fake. For void methods you combine the doAnswer(...).when(mock).method() form.
code
java · 15 linesimport static org.mockito.Mockito.*;
import static org.mockito.AdditionalAnswers.returnsFirstArg;
// Dynamic response computed from the actual arguments
when(greeter.greet(anyString()))
.thenAnswer(inv -> "Hello, " + inv.getArgument(0));
assertEquals("Hello, Ada", greeter.greet("Ada"));
assertEquals("Hello, Bob", greeter.greet("Bob"));
// Echo the saved entity back (simulate a persistence layer)
when(userRepo.save(any(User.class))).thenAnswer(returnsFirstArg());
// equivalently: .thenAnswer(inv -> inv.getArgument(0));
User saved = userRepo.save(new User("Ada"));
assertEquals("Ada", saved.getName());go deeper
Recognizes thenAnswer exists for dynamic responses but typically reaches for thenReturn first.
Can write a thenAnswer lambda using inv.getArgument(i) and knows the eager-vs-per-call difference from thenReturn.
Knows the laziness/argument-dependency trade-offs, uses AdditionalAnswers shortcuts, pairs doAnswer for void, and recognizes over-mocking when an Answer gets too smart.
Sets team guidance on mocks vs. fakes, treats complex Answers as a design smell, and keeps stubs thin and intention-revealing across the codebase's test strategy.
## thenReturn is static; thenAnswer is dynamic `thenReturn(value)` is evaluated **once**, eagerly, the moment you write the stub. Whatever object you computed is stored and handed back on every matching call — it can never depend on *how* the method was called. `thenAnswer(answer)` takes a callback — an `Answer<T>` — that Mockito invokes **every time** the stubbed method is called, *at call time*. The callback receives an `InvocationOnMock` describing the actual call, so the return value can be a *function of the arguments*. ```java when(mock.greet(anyString())) .thenAnswer(inv -> "Hello, " + inv.getArgument(0)); mock.greet("Ada"); // "Hello, Ada" mock.greet("Bob"); // "Hello, Bob" ``` `Answer<T>` is a functional interface — one method `T answer(InvocationOnMock invocation)` — so it's usually written as a lambda. ## Reading the call: InvocationOnMock Key methods: - `inv.getArgument(0)` / `inv.getArgument(0, Foo.class)` — the i-th actual argument, typed. - `inv.getArguments()` — all arguments as an `Object[]`. - `inv.getMock()` — the mock instance. - `inv.getMethod()` — reflective `Method`. ## Canonical use cases **1. Echo the argument back** — e.g. a `save` that returns what it stored: ```java when(repo.save(any(User.class))).thenAnswer(inv -> inv.getArgument(0)); ``` Mockito ships a shortcut: `when(repo.save(any())).thenAnswer(AdditionalAnswers.returnsFirstArg());` (also `returnsSecondArg`, `returnsLastArg`). **2. Compute from inputs:** ```java when(calc.add(anyInt(), anyInt())) .thenAnswer(inv -> (int) inv.getArgument(0) + (int) inv.getArgument(1)); ``` **3. Assign generated state** — return the saved entity with an id set, simulating a DB. **4. Lazy/expensive values** — defer creation until (and unless) the method is actually called. ## thenReturn vs. thenAnswer — eager vs. lazy Because `thenReturn(buildExpensive())` calls `buildExpensive()` immediately at stub time, an exception or cost there happens even if the method is never invoked. `thenAnswer(inv -> buildExpensive())` runs only on actual calls. Prefer `thenReturn` for plain constants (clearer, cheaper); reach for `thenAnswer` when you need the arguments, laziness, or per-call variation that consecutive `thenReturn` can't express. ## void methods and spies `thenAnswer` is only usable in the `when(...).thenAnswer(...)` form, which doesn't work for `void` methods or spies' real-call hazards. For those use **`doAnswer(...).when(mock).voidMethod()`** — the `do*` family is covered separately but pairs naturally here. ## Strict stubs interaction Under strict stubbing (the JUnit5 default), an over-broad `thenAnswer` whose stub is never used is flagged as unnecessary; keep stubs matched to what the test actually exercises. ## When NOT to use it If your `Answer` grows branches and state, you're re-implementing the collaborator inside a stub. That's a smell — switch to a hand-written **fake** (a real, simple in-memory implementation). Mocks/answers are for *thin*, intention-revealing canned behaviour. ## Mental model `thenReturn` is a photo: snapped once, shown forever. `thenAnswer` is a live camera: it re-shoots the scene (the arguments) every time you look, so the picture reflects the current call.
- Your stub is when(repo.save(user)).thenReturn(buildHeavyDefault()). The test never calls save and the build throws. Why does the test still fail, and how does thenAnswer fix it?thenReturn's argument is evaluated eagerly at stubbing time, so buildHeavyDefault() runs (and throws) regardless of whether save is ever called. Switching to thenAnswer(inv -> buildHeavyDefault()) defers the call until the method is actually invoked, so an unused stub never triggers it.
- What's the idiomatic Mockito way to make repository.save(entity) return the same entity passed in?Use AdditionalAnswers.returnsFirstArg(): when(repo.save(any())).thenAnswer(returnsFirstArg()), or equivalently thenAnswer(inv -> inv.getArgument(0)). This echoes the saved object back, simulating a persistence layer that returns what it stored.
saying these in an interview costs you the question
- Thinking thenReturn is re-evaluated each call — it's computed once at stub time.
- Putting heavy branching/state in an Answer instead of using a real fake — that's over-mocking.
- Using getArgument without the type and then doing unchecked casts everywhere (use getArgument(i, Type.class)).
- Trying when(mock.voidMethod()).thenAnswer(...) — void methods need doAnswer().when().