skip to content

Stubbing

Teaching mocks what to return: the when/then API, the do-family it can't replace in every case, dynamic answers, consecutive and void stubbing, and the BDD-flavored alias API. Interviewers love the when-vs-doReturn question because it exposes whether you know how stubbing actually intercepts calls.

on this pageshow

explore

questions

23

In Mockito, how do you make a stubbed method return a different value on each successive call, and what does the mock return once the test calls that method more times than you stubbed for?

level: juniorimportance: must knowfreq 62%

answer

  1. chain thenReturn = queue of answers
  2. thenReturn(a, b, c) varargs shorthand
  3. last answer sticks forever
  4. thenThrow can end the chain
  5. second when() replaces, never appends

basics

~20 s

Chain the answers: when(m.next()).thenReturn(1).thenReturn(2), or use the varargs shorthand thenReturn(1, 2). Calls consume answers in order. Once they run out, the mock keeps repeating the last answer forever — it does not reset, return null, or fail.

solid answer

~50 s

Mockito lets you queue answers for one stubbed call. Two equivalent forms: ```java when(cursor.next()).thenReturn("a").thenReturn("b"); when(cursor.next()).thenReturn("a", "b"); ``` The first invocation gets `"a"`, the second `"b"`. The important semantic is **last-answer persistence**: every invocation after the queue is exhausted repeats the final answer, so the third, fourth and hundredth call all return `"b"`. Mockito never rewinds the sequence and never throws just because you called more times than you stubbed. You can mix outcome kinds in one chain — `thenReturn("a").thenThrow(new IllegalStateException())` returns once then throws on every later call, because the throw is now the sticky last answer. The same queueing exists in the do-family form (`doReturn(1).doThrow(...).when(mock).next()`), which is what you must use when the method returns void. One trap: writing two separate `when(...)` statements for the same call does **not** append answers — the second statement replaces the first.

go deeper

for a junior

Recall the two syntaxes and state plainly that the last answer repeats forever once the queue is exhausted.

for a middle

Add that outcomes can be mixed (thenReturn then thenThrow), that a checked exception must be declared by the method, and that re-stubbing overrides instead of appending.

for a senior

Point out that the sequence never fails on extra calls, so call count must be asserted separately with verify(times(n)), and connect the do-family twin for void methods.

for a principal

Frame long sequences as a coupling smell — the test encodes an exact interaction count — and say when a stateful fake is the better collaborator.

## What consecutive stubbing is for A plain Mockito stub is constant: `when(clock.now()).thenReturn(t)` makes *every* call return the same `t`. Plenty of real collaborators are not constant — an iterator or cursor yields a new element each time, a poller returns `PENDING`, `PENDING`, `DONE`, a flaky client fails then recovers, an ID generator hands out fresh IDs. Consecutive stubbing lets one stubbing statement describe that sequence. ## The two syntaxes Chained calls on the returned `OngoingStubbing`: ```java when(cursor.next()).thenReturn("a").thenReturn("b").thenReturn("c"); ``` and the varargs shorthand, which compiles to exactly the same thing: ```java when(cursor.next()).thenReturn("a", "b", "c"); ``` The signature is `thenReturn(T value, T... values)` — a single-argument overload plus a varargs one — so the shorthand only kicks in when you pass two or more values. Both forms build an ordered queue of *answers* attached to that stubbing. ## Last-answer persistence — the part interviewers probe When the stubbed method is invoked, Mockito pops the next answer from the queue. When only one answer is left, it stops popping and keeps returning that one. So with three answers stubbed: | call | 1 | 2 | 3 | 4 | 5 | |---|---|---|---|---|---| | result | a | b | c | c | c | This is a deliberate design choice, and it is the single most misremembered fact about the feature. Candidates commonly guess that the fourth call returns `null`, that Mockito throws "no more answers", or that the sequence wraps around to the beginning. None of that happens. The practical consequence is that a test can silently pass even if production code calls the collaborator far more often than intended — the sequence never complains, so if call count matters you must assert it with `verify(cursor, times(3)).next()`. ## Mixing answer kinds in one chain The chain is not restricted to values. You can interleave outcomes: ```java when(client.fetch()).thenReturn("ok").thenThrow(new TimeoutException()); ``` First call returns `"ok"`; every call after that throws, because the throw became the sticky last answer. Reverse it to model recovery: ```java when(client.fetch()).thenThrow(new TimeoutException()).thenReturn("ok"); ``` A checked exception must be declared by the stubbed method, or Mockito rejects the stubbing immediately with a `MockitoException` about an invalid checked exception. That check happens at stub time, not at call time, so the failure points at the stubbing line. ## The do-family equivalent Every consecutive form has a do-family twin, built by chaining on the `Stubber`: ```java doReturn("a").doThrow(new IllegalStateException()).when(cursor).next(); ``` Same queue, same last-answer persistence. This matters because methods that return `void` cannot be written in the `when(mock.call())` form at all, so any sequence of behaviours for a void method must be expressed as `doThrow(...).doNothing().when(mock).send(msg)`. ## Re-stubbing is not appending A frequent source of "my second value never shows up": ```java when(cursor.next()).thenReturn("a"); when(cursor.next()).thenReturn("b"); // replaces, does not queue ``` The second statement re-stubs the same invocation, so from then on every call returns `"b"` — you never see `"a"`. Sequences must live in one chain (or one varargs call). The same applies inside loops: building stubs in a `for` loop overwrites rather than accumulates unless you collect the values and pass them as varargs. ## Matchers and sequences The queue belongs to a *stubbing*, which is identified by the method plus its argument matchers. `when(repo.find(1)).thenReturn(a, b)` sequences only calls with argument `1`; a call with `2` falls through to the default answer (`null` for objects, `0` for numbers, empty collections for collection types). If you want one sequence regardless of arguments, stub with `any()`. ## Practical guidance Keep sequences short and obviously intentional — two or three entries that model a named scenario such as "fails once, then succeeds". Long sequences bake exact call counts into the test and break whenever the production code adds a legitimate extra read. When you need more than a handful of steps, the collaborator is usually better replaced by a small hand-written fake that holds real state.

  • If the chain ends with thenThrow, does the mock ever go back to returning a value?
    No. The final entry in the chain becomes the sticky answer, so once the exception entry is reached every subsequent invocation throws a new instance-of-the-same throwable you supplied. If you want failure-then-recovery you must order it the other way: thenThrow(...) first, thenReturn(...) last. There is no wrap-around and no automatic reset between invocations.
  • Does consecutive stubbing also work with the do-family form?
    Yes. Stubber chains the same way: doReturn("a").doThrow(new IllegalStateException()).when(cursor).next(). The queue semantics, including last-answer persistence, are identical. You need this form for void methods, where doThrow(...).doNothing().when(mock).send(msg) is the only way to express a sequence, and for spies, where the when(mock.call()) form would execute the real method.
  • How do you make sure the test notices if production code calls the method more times than the sequence covers?
    Add an explicit verification such as verify(cursor, times(3)).next() or verifyNoMoreInteractions(cursor). Because the last stubbed answer repeats indefinitely, extra calls are invisible to the stubbing itself, so an unbounded retry loop or an accidental double read would still make the test pass. Verification is what turns the sequence into a real assertion about call count.

saying these in an interview costs you the question

  • Claiming the mock returns null, or throws, once the stubbed answers run out
  • Believing the sequence rewinds and replays from the first answer
  • Thinking two separate when(...) statements for the same call queue up answers
  • Assuming reset(mock) is needed between calls to advance the sequence
  • Saying thenReturn(a, b) and .thenReturn(a).thenReturn(b) behave differently

context

open as a page

A teammate tries to stub a method whose return type is void by writing when(service.delete(id)).thenThrow(new IllegalStateException()) in a Mockito test, and it will not compile. Explain why, and show the form that does work.

level: juniorimportance: must knowfreq 58%

basics

~10 s

when(...) takes a value as its argument, and a void call produces no value, so the expression is not legal Java. Use the do-family instead: doThrow(new IllegalStateException()).when(service).delete(id) — behaviour first, stubbed call last.

open as a page

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?

level: juniorimportance: must knowfreq 55%

basics

~10 s

Use 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.

open as a page

Explain how you tell a Mockito mock to return a specific value for a given method call, and what such a mock returns for methods you never stubbed.

level: juniorimportance: must knowfreq 78%

basics

~10 s

Write when(mock.method(args)).thenReturn(value), or thenThrow(exception) for a failure path. Anything you do not stub returns the type's default: null for objects, 0 for numbers, false for boolean, and an empty collection for collection-returning methods.

open as a page

A mailer collaborator's send(...) method has return type void. Using Mockito, how do you stub it so the first invocation throws an IOException and every later invocation succeeds silently?

level: middleimportance: must knowfreq 50%

basics

~10 s

Use the do-family with a chain: doThrow(new IOException()).doNothing().when(mailer).send(any()). First call throws, later calls do nothing, because the last entry in the chain repeats. IOException must be declared by send(...) or Mockito rejects the stub.

open as a page

Why does stubbing a Mockito spy with when(spy.loadAll()).thenReturn(list) still execute the real loadAll() body, and what form avoids that?

level: middleimportance: must knowfreq 66%

basics

~20 s

Java evaluates spy.loadAll() before when() is called, and on a spy an un-stubbed call runs the real method — side effects, database hits, exceptions and all. Use doReturn(list).when(spy).loadAll(), which records the call without invoking it.

open as a page

Mockito's when(mock.findById(1L)) receives the *result* of calling findById rather than a method reference. Explain how it can still register a stub for that call, and what practical consequences the mechanism has.

level: middleimportance: must knowfreq 50%

basics

~20 s

Java evaluates the inner call first: the mock intercepts it, records the invocation (method plus arguments plus matchers) in Mockito's internal state, and returns a default. when() then ignores its argument and attaches the stub to that last recorded invocation. Hence real calls on spies, matcher rules, and unfinished-stubbing errors.

open as a page

Mockito ships a BDDMockito class offering given(...).willReturn(...). How does that relate to the classic when(...).thenReturn(...) stubbing API, and why would a team choose it?

level: juniorimportance: should knowfreq 40%

basics

~20 s

BDDMockito is an alias facade over the same engine. given(mock.call()).willReturn(x) creates exactly the same stubbing as when(mock.call()).thenReturn(x); there is no behavioural difference. Teams use it so tests read given / when / then, reserving the word 'when' for the action under test.

open as a page

In Mockito's BDD API, how do you assert that a collaborator was called a given number of times, never called, or called in a specific order, and how do those forms map to verify(...)?

level: middleimportance: should knowfreq 30%

basics

~10 s

Use then(mock).should(times(2)).save(order), then(mock).should(never()).charge(any()), then(mock).shouldHaveNoInteractions() and then(mock).shouldHaveNoMoreInteractions(). Ordering passes an InOrder object: then(mock).should(inOrder).lock(id). These are exact renamings of verify(mock, times(2)), verify(mock, never()) and verifyNoInteractions.

open as a page

Using Mockito's BDD API, how do you stub a method that returns void, or any method on a spy, and why can that call not be written in the same order as a normal value-returning stubbing?

level: middleimportance: should knowfreq 34%

basics

~20 s

Use the argument-last form: willDoNothing().given(spy).reindex(); willThrow(new IllegalStateException()).given(mailer).send(msg). A void call cannot be passed as an argument to given(...), and on a spy given(spy.call()) would run the real method first. The behaviour is stated before the call is recorded.

open as a page

In Mockito, what is the difference between chaining two answers in a single stubbing — thenReturn(1).thenReturn(2) — and writing two separate when(...) statements for the same call?

level: middleimportance: should knowfreq 40%

basics

~20 s

Chaining inside one statement builds an ordered queue: first call gets 1, second gets 2. Two separate when(...) statements re-stub the same invocation, so the later one replaces the earlier and every call returns 2. Sequences must live in one chain.

open as a page

In Mockito, doReturn(x).when(mock).getValue() and when(mock.getValue()).thenReturn(x) stub the same call. What do you give up by choosing the doReturn form, and when is that trade worth making?

level: middleimportance: should knowfreq 45%

basics

~20 s

doReturn takes a plain Object, so the compiler cannot check that the value matches the method's return type — a mismatch only surfaces at runtime as WrongTypeOfReturnValue. It is worth it for spies, void methods, and generics cases where thenReturn will not compile.

open as a page

Mockito ships an AdditionalAnswers utility class alongside hand-written Answer lambdas. Which helpers does it provide, and when would you use them instead of writing the lambda yourself?

level: middleimportance: should knowfreq 30%

basics

~10 s

AdditionalAnswers offers ready-made answers: returnsFirstArg / returnsSecondArg / returnsLastArg to echo an argument, returnsElementsOf(collection) to walk a list, delegatesTo(realObject) to forward calls to a real implementation, and answersWithDelay(millis, answer) to simulate latency.

open as a page

Inside a Mockito Answer callback you are handed an InvocationOnMock object. What information and operations does it expose, and what is each one typically used for?

level: middleimportance: should knowfreq 40%

basics

~20 s

InvocationOnMock describes the current call: getArgument(i) / getArguments() for the arguments, getMethod() for the reflective method, getMock() for the mock itself (handy for fluent builders returning this), and callRealMethod() to delegate to the real implementation on a spy or partial mock.

open as a page

Mockito rejects some stubbed exceptions with the message "Checked exception is invalid for this method". What rule is it enforcing, and what are your options when you hit it?

level: middleimportance: should knowfreq 40%

basics

~20 s

A stubbed checked exception must be declared in the stubbed method's throws clause (or be a subtype of a declared one). Unchecked exceptions are always allowed. Options: throw a declared or unchecked exception, or change the interface if the failure is real.

open as a page

How would you use Mockito to test that a retry policy re-invokes a flaky collaborator — failing twice, then succeeding — and what should the test assert beyond the final result?

level: seniorimportance: should knowfreq 42%

basics

~20 s

Stub a sequence: two failures then success (doThrow().doThrow().doNothing() for void, or thenThrow().thenThrow().thenReturn() for a value). Assert the successful outcome AND verify(collaborator, times(3)) — because the last stubbed answer repeats forever, extra retries would otherwise go unnoticed.

open as a page

A teammate stubs a mock repository with a thenAnswer that keeps an internal HashMap of saved entities and serves findById from it. What are the risks of this style of stubbing, and when would you push back?

level: seniorimportance: should knowfreq 35%

basics

~20 s

An Answer holding state is a second, untested implementation of the collaborator hidden in test setup. Risks: the test validates code against that stand-in, state leaks between tests, and the Answer is not thread-safe unless you make it so. If it needs state, write an explicit fake.

open as a page

In a Mockito test the same collaborator call is stubbed twice - once in a @BeforeEach setup method and again at the top of a single test. Which stubbing wins, and what else should you know about overriding stubs?

level: seniorimportance: should knowfreq 38%

basics

~20 s

The later stubbing wins: Mockito searches registered stubbings newest-first and uses the first whose matchers fit. The setup stub still exists, and if it is never used, strict-stubs mode reports it as an UnnecessaryStubbing failure.

open as a page

What does Mockito's thenCallRealMethod() do, when is it the right tool, and what surprises people about using it on an object created with Mockito.mock() rather than spy()?

level: middleimportance: nice to knowfreq 25%

basics

~20 s

thenCallRealMethod() makes one stubbed method execute its real body instead of returning a default, creating a partial mock. The surprise: mock() builds the instance without running a constructor, so fields are uninitialised and real methods often hit NullPointerException - spy() over a constructed object avoids that.

open as a page

A Java codebase mixes Mockito's classic when/verify calls and its BDD given/then calls inside the same test classes. What practical problems does that create, and how would you settle a convention for the team?

level: seniorimportance: nice to knowfreq 22%

basics

~20 s

Nothing breaks technically, but readers lose the given/when/then rhythm, reviews re-argue style per file, and Mockito's static then(...) collides with AssertJ's then(...). Pick one style, enforce it with an import rule in the linter or an architecture test, and migrate opportunistically rather than in a mass rewrite.

open as a page

What does Mockito's doCallRealMethod() do, and how does using it on a plain mock differ from creating a spy over a real instance?

level: seniorimportance: nice to knowfreq 32%

basics

~20 s

doCallRealMethod() makes one stubbed method run its real implementation. On a plain mock the object was created without running any constructor, so its fields are null or zero and the real method often fails; a spy copies a fully constructed instance's state, so real methods usually work.

open as a page

When is stubbing a collaborator to return a different value on each successive call the wrong tool for a test, and what would you use instead?

level: principalimportance: nice to knowfreq 26%

basics

~20 s

It is wrong when the sequence encodes how many times the code calls the collaborator rather than what it does. That couples the test to the implementation's call pattern. Prefer a small stateful fake, or state-based assertions, when the collaborator has real behaviour over time.

open as a page

Should a team standardize on Mockito's do-family stubbing form everywhere for consistency, or keep when(...).thenReturn(...) as the default and use the do-family only where required? Argue your position.

level: principalimportance: nice to knowfreq 22%

basics

~20 s

Keep when(...).thenReturn(...) as the default. It is compile-time type-checked and reads in the natural order. Use the do-family only where it is required — spies, void methods, awkward generics, doCallRealMethod — so its presence signals a special case rather than a style choice.

open as a page