skip to content

when / thenReturn / thenThrow

The canonical stubbing form: when(mock.call()).thenReturn/thenThrow/thenCallRealMethod. You should be able to explain how the call inside when() is recorded rather than executed, and what checked-exception rules thenThrow enforces.

on this pageshow

questions

5

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%

answer

  1. when(mock.call(args)).thenReturn(value)
  2. thenThrow(instance) or thenThrow(Class) via no-arg ctor
  3. thenCallRealMethod for the real body
  4. unstubbed -> null / 0 / false / empty collection
  5. missing stub shows up as an NPE in production code

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.

solid answer

~40 s

Stubbing reads as `when(mock.someCall(args)).thenReturn(value)`: ```java UserRepository repo = mock(UserRepository.class); when(repo.findById(1L)).thenReturn(new User(1L, "ada")); when(repo.findById(99L)).thenThrow(new NotFoundException()); ``` The arguments in the `when(...)` call form the match: the stub fires only for calls whose arguments are equal (by `equals`) to those, or that satisfy the argument matchers you used instead of literals. `thenThrow` sets the error path - either an instance or a class, in which case Mockito constructs it with the no-arg constructor. `thenCallRealMethod()` routes to the real implementation. Unstubbed methods do not fail. A default Mockito mock returns the zero value for the return type: `null` for object types, `0`/`0.0` for numbers, `false` for `boolean`, and empty `List`/`Set`/`Map`/`Optional.empty()` for collection-ish types. That is why a forgotten stub usually shows up as a NullPointerException in the code under test rather than as a Mockito error.

code

java · 9 lines
java
UserRepository repo = mock(UserRepository.class);

when(repo.findById(1L)).thenReturn(new User(1L, "ada"));
when(repo.findById(99L)).thenThrow(new NotFoundException("no user 99"));

assertEquals("ada", repo.findById(1L).getName());
assertThrows(NotFoundException.class, () -> repo.findById(99L));
assertNull(repo.findById(2L));          // unstubbed object return
assertEquals(List.of(), repo.findAll()); // unstubbed collection return

go deeper

for a junior

Show the syntax confidently and state the defaults for unstubbed calls: null, 0, false, empty collections.

for a middle

Add matching semantics (equals or matchers, all-or-nothing), the thenThrow class-versus-instance difference, and why a missing stub shows up as an NPE.

for a senior

Connect defaults to diagnosis and test hygiene: stub only what is needed, prefer specific arguments over any(), let strict stubs catch dead stubbings.

for a principal

Discuss what stubbing says about design - how many stubs a test needs is a proxy for a collaborator's chattiness - and where fakes beat piles of stubs.

## The shape of a stub Mockito's core stubbing form is: ```java when(mock.methodCall(arguments)).thenReturn(value); ``` Read it as "when this call happens, then return this". The chain after `when(...)` is called the `OngoingStubbing`, and it offers `thenReturn`, `thenThrow`, `thenCallRealMethod`, and `thenAnswer`. ## Matching The arguments you write inside `when(...)` define which calls the stub covers. Literals are compared with `equals()`, so `when(repo.findById(1L))` matches only the call with `1L`. Matchers such as `any()`, `eq()`, `argThat(...)` broaden that. The rule to remember early: if you use a matcher for one argument you must use matchers for all of them - mixing a raw literal with a matcher raises `InvalidUseOfMatchersException`. A call that matches no stubbing simply falls back to the mock's default answer. ## thenReturn `thenReturn(value)` stores a single already-computed value. The expression you pass is evaluated once, at stubbing time, and the same reference is returned to every matching call - which matters if the object is mutable and the code under test mutates it. Type compatibility is enforced by the compiler through generics in the common case, so a mismatch is usually a compile error rather than a runtime surprise. ## thenThrow `thenThrow(new IllegalStateException("boom"))` makes the matching call throw. There is also `thenThrow(IllegalStateException.class)`, where Mockito instantiates the exception itself using the no-arg constructor - convenient, but it produces an exception with no message, which makes a failing assertion less informative. There is one rule Mockito enforces: a **checked** exception may only be stubbed if the method declares it (or a supertype of it) in its `throws` clause. Otherwise you get "Checked exception is invalid for this method". Unchecked exceptions and `Error`s are always allowed. The usual test then asserts on it: ```java when(repo.findById(99L)).thenThrow(new NotFoundException()); assertThrows(NotFoundException.class, () -> service.load(99L)); ``` ## thenCallRealMethod `thenCallRealMethod()` tells the mock to execute the real body for that method, turning the mock into a partial mock for that one call. It requires a real implementation to exist, so it does not work for interface or abstract methods. ## What an unstubbed method returns Every Mockito mock has a default answer, `RETURNS_DEFAULTS`, which produces the type's zero value: - object types -> `null` - `int`, `long`, `double`, ... -> `0` - `boolean` -> `false` - `List`, `Set`, `Map`, `Collection`, `Stream`, `Optional` -> empty instances, not `null` This is deliberate: a mock is usable straight out of `mock(...)` and you stub only what the test cares about. The practical consequence is that a missing stub does not announce itself. The code under test receives `null`, dereferences it, and you debug an NPE that points at your production code rather than at the test. When a test fails with an NPE on a collaborator's result, check for a missing or mis-matched stub first. Alternative default answers exist for other trade-offs, but the plain default is what you get from `mock(Foo.class)` and from `@Mock`. ## Practical habits - Stub in the arrange section, assert in the assert section - do not scatter `when(...)` through the test. - Stub only what the test needs; with strict stubs, unused stubbings are reported as errors, which keeps tests honest. - Prefer specific argument values over `any()` when the arguments are part of what you are asserting; a stub that matches everything can hide a bug in how the arguments are built. - Remember stubbing is per mock instance: two mocks of the same interface share nothing.

  • Your test fails with a NullPointerException inside the class under test, not in the test itself. How does that relate to stubbing?
    Most often a collaborator call was never stubbed, so the mock returned null and the production code dereferenced it. Check which mock call happens on that line and whether the arguments actually match a stubbing you wrote - an argument mismatch has the same effect as no stub at all. Adding the missing stub, or fixing the matcher, resolves it.
  • What is the difference between thenThrow(new IllegalStateException("boom")) and thenThrow(IllegalStateException.class)?
    The first throws exactly the instance you built, message and all. The second asks Mockito to instantiate the exception via its no-arg constructor, so the thrown exception has no message and the class must actually have such a constructor. The instance form is preferable when the message or any field matters to the assertion or to the failure output.

saying these in an interview costs you the question

  • Expecting an unstubbed mock method to throw or fail loudly instead of returning a default
  • Thinking unstubbed collection-returning methods give null - they return empty collections
  • Mixing raw argument values and matchers in the same when(...) call
  • Believing a stub on one mock instance affects another mock of the same type
  • Assuming thenReturn re-evaluates its argument expression on each call

context

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

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