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.
answer
- when(mock.call(args)).thenReturn(value)
- thenThrow(instance) or thenThrow(Class) via no-arg ctor
- thenCallRealMethod for the real body
- unstubbed -> null / 0 / false / empty collection
- missing stub shows up as an NPE in production code
basics
~10 sWrite 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 sStubbing 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 linesUserRepository 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 returngo deeper
Show the syntax confidently and state the defaults for unstubbed calls: null, 0, false, empty collections.
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.
Connect defaults to diagnosis and test hygiene: stub only what is needed, prefer specific arguments over any(), let strict stubs catch dead stubbings.
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