skip to content

Creating Mocks

The two ways to conjure a mock — mock() calls and the @Mock annotation — and the per-mock settings you can attach at creation time. You should be able to explain what an unstubbed mock returns by default and when you'd reach for withSettings().

on this pageshow

questions

5

You create a Mockito mock of a Java interface and then call a method on it that you never stubbed. What does that call return, and what else happens?

level: juniorimportance: must knowfreq 78%

answer

  1. RETURNS_DEFAULTS = ReturnsEmptyValues
  2. null / 0 / false; empty List, Map, Stream, Optional
  3. Integer null -> unboxing NPE
  4. chained call on unstubbed getter = NPE
  5. still recorded for verify()

basics

~20 s

No real code runs. Mockito returns the type's default value: null for objects, 0 for numbers, false for boolean, and an empty collection, Optional or stream for those types. Void methods do nothing. The call is recorded so you can verify it later.

solid answer

~50 s

A mock created by `Mockito.mock()` is a generated object whose every method is intercepted; none of the real implementation runs. Unstubbed calls go to the default answer, `RETURNS_DEFAULTS`, which is implemented by `ReturnsEmptyValues`: primitives get their JVM default (`0`, `0.0`, `false`, `''`), primitive wrappers and every other object type get `null`, but well-known empty types are special-cased — `List`, `Set`, `Map`, `Stream`, `Optional` and friends come back empty rather than null. Void methods are no-ops. Two practical consequences: first, calling a method on a mock is safe, so you only stub what the test cares about; second, chaining off an unstubbed object-returning call gives a `NullPointerException`, which is the single most common surprise for beginners. Every call is still recorded in the mock's invocation list, so `verify()` sees it even though it returned a default.

code

java · 10 lines
java
OrderRepository repo = Mockito.mock(OrderRepository.class);

assertNull(repo.findById(1L));          // object -> null
assertEquals(0, repo.countAll());        // int -> 0
assertFalse(repo.exists(1L));            // boolean -> false
assertTrue(repo.findAll().isEmpty());    // List -> empty, not null
assertTrue(repo.findLatest().isEmpty());  // Optional -> Optional.empty()

repo.deleteById(1L);                     // void -> no-op
verify(repo).deleteById(1L);             // ...but still recorded

go deeper

for a junior

Recall the table: null for objects, 0/false for primitives, empty collection or Optional, void does nothing — and that no real code runs.

for a middle

Add the mechanism (RETURNS_DEFAULTS/ReturnsEmptyValues), the wrapper-unboxing trap, and that calls are still recorded for verification.

for a senior

Talk about diagnosing the chained-call NPE, when RETURNS_SMART_NULLS earns its keep during debugging, and why you would not make throwing-on-unstubbed the team default.

for a principal

Frame defaults as a policy choice: permissive defaults keep tests focused on one behaviour, strict answers surface hidden coupling; pick per-codebase and prefer fixing the design over tuning the default answer globally.

## What a mock actually is When you write `PaymentGateway gateway = Mockito.mock(PaymentGateway.class);` Mockito generates a new class at runtime that implements (or extends) the given type and routes every method call into its own interception machinery instead of the real body. So there is no partially-real object here: the mock has no meaningful state, no constructor logic, and no behaviour beyond what you give it. Because the mock still has to return *something* when a method has a return type, Mockito consults the mock's **default answer**. Unless you say otherwise, that answer is `Answers.RETURNS_DEFAULTS`, whose implementation class is `ReturnsEmptyValues`. ## The default value table `ReturnsEmptyValues` resolves an unstubbed call like this: - **Primitives** get the JVM default: `int`/`long`/`short`/`byte` → `0`, `double`/`float` → `0.0`, `boolean` → `false`, `char` → `''`. - **Primitive wrappers** (`Integer`, `Boolean`, …) → `null`. This asymmetry bites: a method declared `int count()` returns `0`, but `Integer count()` returns `null`, and auto-unboxing that into an `int` throws `NullPointerException`. - **Known empty-able types** → an empty instance, not null: `Collection`, `List`, `Set`, `SortedSet`, `Map`, `SortedMap`, `Iterable`, `Iterator`, `Stream`, `IntStream`/`LongStream`/`DoubleStream`, `Optional`, `OptionalInt`/`OptionalLong`/`OptionalDouble`, and `Duration`/`Period` (zero). Each call returns a fresh empty instance, so you must not rely on identity between two calls. - **Everything else** (your domain classes, `String`, arrays) → `null`. - **`void`** → nothing happens at all; the call simply returns. A handful of methods are handled specially rather than defaulted: `equals()` and `hashCode()` cannot be stubbed or intercepted (Mockito needs them for its own bookkeeping), and `toString()` returns a readable name such as `Mock for PaymentGateway, hashCode: 12345`. ## Why empty collections instead of null Returning an empty list is a deliberate ergonomic choice: production code overwhelmingly iterates over returned collections, and a null would blow up in code under test that is behaving perfectly correctly. The empty value keeps the *unspecified* parts of a collaborator harmless so your test only has to describe the interesting part. ## The classic failure it causes ```java OrderRepository repo = mock(OrderRepository.class); // findById is unstubbed -> returns null String id = repo.findById(1L).getCustomerId(); // NullPointerException ``` The NPE is not a Mockito bug; it is Mockito telling you that you never described what `findById` should do. The fix is to stub it (`when(repo.findById(1L)).thenReturn(order)`), not to work around the null. When such NPEs are frequent and hard to trace, you can create the mock with `Answers.RETURNS_SMART_NULLS`, which returns a placeholder object that throws a `SmartNullPointerException` naming the unstubbed method and the line where the mock was used — a much better diagnostic. ## Changing the default deliberately The default answer is a creation-time setting, so it is chosen where the mock is made: - `mock(Foo.class, Answers.RETURNS_SMART_NULLS)` — diagnostic nulls, useful while debugging. - `mock(Foo.class, Answers.RETURNS_MOCKS)` — every object-returning method returns another mock instead of null. - `mock(Foo.class, Answers.RETURNS_DEEP_STUBS)` — like `RETURNS_MOCKS`, but the chain is remembered so `when(a.getB().getC()).thenReturn(x)` works. - `mock(Foo.class, Answers.CALLS_REAL_METHODS)` — unstubbed calls execute the real body. - `mock(Foo.class, withSettings().defaultAnswer(myAnswer))` — a custom `Answer` implementation, e.g. one that throws for anything unstubbed so no accidental default can slip through. - With the annotation form: `@Mock(answer = Answers.RETURNS_SMART_NULLS)`. Using a strict custom answer that throws is occasionally used on legacy code to force every interaction to be made explicit; the cost is noisy tests, so it is a temporary tool rather than a default. ## Defaults and verification Returning a default does not mean the call was ignored. Every invocation on a mock is appended to its invocation list, so `verify(gateway).charge(amount)` passes even though `charge` was never stubbed and returned `false`/`null`. This is exactly why stubbing and verification are separable: you stub what the code needs to keep running, and you verify what the code was supposed to do. ## What to say in an interview State the rule (nulls/zeros/false, empty collections and `Optional`), name `RETURNS_DEFAULTS`/`ReturnsEmptyValues`, mention the wrapper-unboxing trap and the chained-call NPE, and finish with the fact that the call is still recorded for verification. That is a complete answer at any level.

  • A test throws NullPointerException on a line that only calls a method on the result of a mocked call. What is the cause and the fix?
    The inner method was never stubbed, so it returned the default `null`, and the outer call dereferenced it. The fix is to stub the inner call with `when(...).thenReturn(...)` (or return an `Optional`/empty value the code can handle), not to null-guard production code for the test's benefit. If this happens often while exploring an unfamiliar codebase, create the mock with `RETURNS_SMART_NULLS` so the failure message names the unstubbed method.
  • How would you make every unstubbed method on one particular mock throw instead of returning a default?
    Pass a custom `Answer` as the default answer at creation: `mock(Foo.class, withSettings().defaultAnswer(inv -> { throw new UnsupportedOperationException(inv.getMethod().getName()); }))`. It is a per-mock setting, so it does not affect other mocks. It is useful to smoke out hidden interactions in legacy code, but as a permanent default it makes tests brittle and verbose.
  • Does returning a default value mean Mockito did not record the call?
    No. Every invocation on a mock is recorded in its invocation list regardless of whether it was stubbed, so `verify()` and `InOrder` see unstubbed calls too. Stubbing controls what comes back; recording is unconditional. That is why you can verify a void method that by definition returns nothing.

A mock is a stand-in actor who has been handed only the lines you wrote. Ask anything else and they shrug: silence for void, an empty hand for collections, nothing at all for objects.

saying these in an interview costs you the question

  • Saying an unstubbed method throws an exception or fails the test by default
  • Saying the real implementation runs on a mock created with mock()
  • Claiming a mocked method returning List gives null (it gives an empty list)
  • Assuming every method must be stubbed before it can be called
  • Thinking an unstubbed call is not recorded and therefore cannot be verified

context

open as a page

What are the ways to create a Mockito mock in a Java test, and what practical difference is there between calling Mockito.mock(Foo.class) and declaring a field annotated with Mockito's @Mock?

level: juniorimportance: should knowfreq 66%

basics

~20 s

Two forms produce the same kind of object: the programmatic Mockito.mock(Foo.class) (optionally with settings) and the declarative @Mock Foo foo; field. The annotation is shorter, names the mock after the field for better failure messages, and needs an initializer to run; mock() works anywhere, including inside a method or with generics.

open as a page

When Mockito creates a mock of a concrete Java class, is that class's constructor executed and are its fields initialized? Explain how the mock object comes into existence.

level: middleimportance: should knowfreq 48%

basics

~20 s

No constructor runs and no field initializer runs. Mockito generates a subclass (or, with the inline mock maker, instruments the class) and allocates an instance without calling any constructor, using Objenesis. All fields stay at their JVM defaults, and every method is intercepted, so no real code executes.

open as a page

Mockito's mock() has an overload that takes a MockSettings built by withSettings(). Which of those settings do you actually use, and what problem does each one solve?

level: middleimportance: should knowfreq 38%

basics

~20 s

The ones that earn their keep: name(...) for readable failure messages, defaultAnswer(...) to change what unstubbed calls return, lenient() to exempt one mock from unused-stub checking, extraInterfaces(...) when code casts the collaborator to another type, plus serializable(), stubOnly() and verboseLogging() for narrower cases.

open as a page

What does creating a Mockito mock with Answers.RETURNS_DEEP_STUBS do, and when is choosing it a warning sign rather than a solution?

level: seniorimportance: nice to knowfreq 32%

basics

~20 s

Deep stubs make every object-returning method return another deep-stub mock, remembered per call, so when(a.getB().getC()).thenReturn(x) works without stubbing each level. It is convenient for hostile third-party APIs, but a chain you must deep-stub usually signals a Law-of-Demeter violation in your own code.

open as a page