skip to content

How do you make a mock throw on the first call but succeed on retries, and when would you reach for thenAnswer/doAnswer instead of thenThrow?

level: seniorimportance: nice to knowfreq 35%

answer

  1. chain: thenThrow(...).thenReturn(...) → per-call
  2. last stub is sticky
  3. doThrow(...).doNothing().when(mock).voidM() for void
  4. thenAnswer sees InvocationOnMock + getArgument(i)
  5. keep Answers thin → else use a fake

basics

~10 s

Chain stubs: when(mock.call()).thenThrow(new TimeoutException()).thenReturn(value). The first call throws, later calls return. Use thenAnswer/doAnswer when whether (or what) to throw depends on the actual arguments.

solid answer

~40 s

Mockito applies chained stubs to consecutive calls: when(mock.call()).thenThrow(new TimeoutException()).thenReturn(user) throws on the first invocation and returns user on every call after — perfect for testing retry logic. The last stub is sticky once reached. For void methods the do-chain is doThrow(ex).doNothing().when(mock).flush(). When the decision to throw depends on the arguments or call count, thenThrow isn't expressive enough; use thenAnswer (or doAnswer for void/spies). The Answer receives an InvocationOnMock, lets you read arguments via invocation.getArgument(i), and you can conditionally throw or compute a return. Keep Answers small — heavy logic in an Answer is a smell suggesting a hand-written fake or a real object would read better.

code

java · 12 lines
java
// Fail twice then succeed — testing retry logic
when(client.fetch())
    .thenThrow(new TimeoutException())
    .thenThrow(new TimeoutException())
    .thenReturn(payload);

// Argument-dependent throwing
when(repo.find(anyLong())).thenAnswer(inv -> {
    long id = inv.getArgument(0);
    if (id < 0) throw new IllegalArgumentException("id < 0");
    return new User(id);
});

go deeper

for a junior

Knows you can chain thenThrow().thenReturn() so the first call fails and later calls succeed.

for a middle

Explains chaining and last-stub stickiness, and the do-chain for void methods.

for a senior

Reaches for thenAnswer/doAnswer for argument-dependent throwing, reads InvocationOnMock, and knows the do-form for spies.

for a principal

Judges when an Answer is too heavy and a hand-written fake or real object yields clearer, more maintainable tests; sets retry-testing patterns.

## Consecutive-call stubbing Mockito lets a single stub define a **sequence** of behaviours, one per successive call, by chaining: ```java when(client.fetch()) .thenThrow(new TimeoutException()) // call #1 .thenThrow(new TimeoutException()) // call #2 .thenReturn(payload); // call #3 and onward ``` Rules: - Each chained item maps to the next invocation in order. - Once the **last** item is reached it becomes **sticky** — every further call repeats it. - You can freely mix `thenThrow` and `thenReturn` in one chain. A shorthand: `thenThrow(A.class, B.class)` (or `thenThrow(a, b)`) passes several exceptions at once, equivalent to chaining them. This is the canonical way to test **retry** logic: "fail twice, then succeed — assert the code retried and eventually returned the value." For **void** methods use the do-chain: ```java doThrow(new IllegalStateException()).doNothing().when(buffer).flush(); ``` ## When thenThrow isn't enough: thenAnswer / doAnswer `thenThrow` and `thenReturn` are **static** — they don't see the call's arguments. When the behaviour must depend on *what was passed* (or other dynamic state), use an **`Answer`**: ```java when(repo.find(anyLong())).thenAnswer(invocation -> { long id = invocation.getArgument(0); if (id < 0) throw new IllegalArgumentException("id < 0"); return new User(id); }); ``` An `Answer<T>` is a callback that receives an **`InvocationOnMock`**, exposing: - `getArgument(int)` — a typed argument by position, - `getArguments()` — all args, - `getMock()` — the mock itself, - `callRealMethod()` — invoke the real implementation (useful on spies). From inside the lambda you can **conditionally throw** an exception, compute a return based on inputs, or track call counts. `doAnswer(...).when(mock).method()` is the void-/spy-safe form. ## Choosing between them | Need | Use | |---|---| | Always throw the same exception | `thenThrow` / `doThrow` | | Different behaviour per successive call | chained `thenThrow().thenReturn()...` | | Behaviour depends on arguments / dynamic state | `thenAnswer` / `doAnswer` | | Void method, any of the above | the `do*` family | ## Caution: keep Answers thin An `Answer` is real code running inside your test. Large, branchy Answers are hard to read and often re-implement the very logic you're trying to fake. If an Answer grows, prefer a small **hand-written fake/stub class** or a real object — the test will be clearer. Reserve Answers for genuinely argument-dependent behaviour. ## Summary - Chain stubs for per-call behaviour; the last one sticks. - `thenAnswer`/`doAnswer` give access to the invocation so you can throw or return based on arguments. - Use the `do*` forms for void methods and spies; keep Answers small.

  • What happens on the 4th call if you chained three behaviours?
    The third (last) behaviour repeats — the final stub in a chain is sticky for all subsequent calls.
  • How does an Answer read the method arguments?
    Through the InvocationOnMock passed to it, e.g. invocation.getArgument(0) or invocation.getArguments().

saying these in an interview costs you the question

  • Thinking each call re-runs the whole chain (it advances and then sticks on the last)
  • Using thenThrow when behaviour must depend on arguments (needs thenAnswer)
  • Putting heavy logic inside an Answer instead of a hand-written fake

context