In a Mockito test you need a mock's return value to depend on the arguments of the call - for example a repository mock whose save() gives back whatever entity was passed in. How do you configure that stub, and how does it differ from stubbing a fixed value?
answer
- thenReturn = value, thenAnswer = function
- Answer.answer(InvocationOnMock)
- inv.getArgument(0) echoes save()
- thenReturn evaluated once at stub time
- WrongTypeOfReturnValue at call time
basics
~10 sUse thenAnswer instead of thenReturn: when(repo.save(any())).thenAnswer(inv -> inv.getArgument(0)). The lambda is an Answer that Mockito runs on every matching call, so the result is computed per call from the real arguments.
solid answer
~50 s`thenReturn(x)` binds a single value, evaluated once at stubbing time and handed back on every call. When the result must depend on the call, use `thenAnswer(Answer)`: ```java when(repo.save(any(User.class))) .thenAnswer(inv -> inv.<User>getArgument(0)); ``` `Answer<T>` has one method, `T answer(InvocationOnMock invocation)`, so a lambda works. Mockito invokes it on every matching invocation and hands it an `InvocationOnMock` describing that call: its arguments, the method, and the mock itself. Typical uses: echo back a saved entity, attach a generated id to the argument, return a value keyed off an argument, or invoke a callback that was passed in. Two caveats. The lambda's result is checked against the stubbed method's return type at call time, not compile time, so mistakes surface as Mockito's `WrongTypeOfReturnValue`. And the body should stay one or two lines - a long answer is production logic re-implemented in a test.
code
java · 8 lineswhen(userRepository.save(any(User.class))).thenAnswer(invocation -> {
User arg = invocation.getArgument(0, User.class);
return new User(42L, arg.getName());
});
User saved = service.register("ada");
assertEquals("ada", saved.getName());
assertEquals(42L, saved.getId());go deeper
Know the syntax and that the lambda receives the invocation: when(mock.save(any())).thenAnswer(inv -> inv.getArgument(0)).
Explain evaluation time - thenReturn's expression runs once at stub time, the Answer runs per call - and mention that return-type mismatches fail at call time.
Frame it as a judgement call: use dynamic answers for echo/callback cases, and treat a growing Answer as a signal to switch to a hand-written fake.
Talk about where behaviour should live in a test suite: mocks encode interaction expectations, and moving too much behaviour into Answers quietly builds a second, untested implementation the suite then validates itself against.
## What a fixed stub does `when(repo.findById(1L)).thenReturn(user)` pairs a call pattern with a constant. The constant is produced **once**, while the test sets up, and the identical object is returned on every matching call. That is correct for most stubs: a test usually wants a known, boring value so it can assert on the code under test rather than on the collaborator. It breaks down as soon as the value has to be a function of the call. Classic cases: - `save(entity)` in a JPA-style repository returns the persisted entity (often with a generated id). Returning a fixed unrelated object, or `null`, makes the code under test behave nothing like production. - A lookup that must answer differently per key. - An API that takes a callback and is expected to invoke it. ## The Answer interface `org.mockito.stubbing.Answer<T>` is a single-abstract-method interface: ```java public interface Answer<T> { T answer(InvocationOnMock invocation) throws Throwable; } ``` Because it is a SAM type you pass a lambda. `when(...).thenAnswer(lambda)` registers it; Mockito then calls `answer(...)` **on every invocation that matches the stubbing**, and whatever it returns becomes the call's return value. The `InvocationOnMock` parameter is a description of that specific call - `getArgument(int)` for a typed argument, `getArguments()` for all of them, `getMock()` for the mock instance, `getMethod()` for the reflective method. So the mental model is: `thenReturn` = a value; `thenAnswer` = a function from the invocation to a value. ## Evaluation time is the real difference The most common misunderstanding is thinking `thenReturn` re-evaluates its expression. It does not. `when(idGen.next()).thenReturn(counter.incrementAndGet())` increments the counter exactly once - Java evaluates the argument before `thenReturn` is even entered - and every call to `next()` returns that same number. To get a fresh number per call you need `thenAnswer(inv -> counter.incrementAndGet())`. ## Type safety `getArgument(int)` is generically typed and performs an unchecked cast, so an index or type mistake blows up at call time with a `ClassCastException`. Similarly, if the lambda returns a type incompatible with the stubbed method, Mockito raises `WrongTypeOfReturnValue` when the mock is called, not when the stub is written. Using the explicit form `inv.getArgument(0, User.class)` or a typed local variable makes the failure earlier and the intent clearer. ## A word on scope `thenAnswer` chains off `when(...)`, which requires the stubbed method to return a value. Void methods and spies have their own `do...` entry point, which is a separate topic; the `Answer` object itself is the same abstraction in both places. ## Keep answers small An `Answer` is executable code inside a test, and it is not itself covered by tests. Two-line answers - echo an argument, throw based on an argument, invoke a callback - are fine and idiomatic. Once an answer grows a switch statement or a map of state, you have written a second implementation of the collaborator, and the test now verifies your code against that second implementation. At that point a hand-written fake, or the real class with in-memory wiring, is usually more honest and more readable. ## Quick checklist - Value depends on arguments -> `thenAnswer`. - Value must change per call -> `thenAnswer` (or consecutive stubbing, a different tool). - Value is a constant -> stay with `thenReturn`; it is simpler and the failure messages are better.
- Your Answer lambda returns a String but the stubbed method returns Integer. When and how do you find out?Not at compile time - thenAnswer is typed loosely enough that the mismatch slips through. Mockito detects it when the mock is actually called and throws WrongTypeOfReturnValue naming the method and the offending type. Declaring a typed local variable inside the lambda, or using getArgument(0, Foo.class), moves the mistake closer to where it was made.
- When would you reach for an ArgumentCaptor instead of writing an Answer that records arguments?When you only want to inspect what was passed, not influence what is returned. A captor pairs with verify() and keeps the assertion in the assert phase, where it reads naturally. An Answer that stashes arguments into a field mixes stubbing and verification and hides the assertion in setup. Use the Answer only when the return value genuinely depends on the input.
thenReturn is a printed photo handed out to everyone who asks; thenAnswer is a camera that takes a new picture of whoever walks up.
saying these in an interview costs you the question
- Believing thenReturn re-evaluates its argument expression on every call
- Writing thenAnswer for a constant value, where thenReturn is simpler and clearer
- Assuming getArgument is type-checked at compile time
- Growing an Answer into a full re-implementation of the collaborator
- Thinking the Answer runs once at stubbing time rather than on each matching invocation