skip to content

Mocks, Spies & Injection

How test doubles come into existence in Mockito: programmatic and annotation-driven mocks, partial-mock spies, dependency injection into the class under test, and the initialization plumbing that wires it all up. Interviewers ask here first because misusing @InjectMocks or forgetting to initialize annotations is the most common Mockito failure in real codebases.

on this pageshow

explore

questions

19

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

A test class declares fields annotated with Mockito's @Mock, and the test fails with NullPointerException the first time one of those fields is used. Why are they null, and what are the ways to make them non-null?

level: juniorimportance: must knowfreq 62%

basics

~20 s

@Mock is only metadata; something must scan the test instance and assign the mocks. Enable one initializer: @ExtendWith(MockitoExtension.class) on JUnit 5, MockitoAnnotations.openMocks(this) in a setup method, or the JUnit 4 MockitoJUnitRunner/MockitoRule. Without one, the fields stay null.

open as a page

In Mockito, what does the @InjectMocks annotation do to the field it is placed on, and where does it get the values it injects?

level: juniorimportance: must knowfreq 70%

basics

~20 s

@InjectMocks makes Mockito create a real instance of that field's type and push the test class's @Mock and @Spy fields into it as dependencies. The field under test is a real object, not a mock — only its collaborators are mocks.

open as a page

In Mockito, what does Mockito.spy(new ArrayList<String>()) give you that Mockito.mock(ArrayList.class) does not — specifically, what happens when you call a method you never stubbed?

level: juniorimportance: must knowfreq 68%

basics

~20 s

On a mock, an unstubbed method does nothing and returns a default — null, 0, false, or an empty collection. On a spy, an unstubbed method runs the real implementation. Both record calls, so both can be verified.

open as a page

Compare registering Mockito's JUnit 5 extension with calling MockitoAnnotations.openMocks(this) in a setup method: what does the extension give you that the manual call does not, and when would you still choose the manual call?

level: middleimportance: must knowfreq 50%

basics

~20 s

Both create the annotated mocks per test. The extension additionally applies strict stubs (failing on unused or mismatched stubbings), validates Mockito usage after each test, closes the session for you, and can inject mocks as test-method parameters. openMocks does none of that but works in any framework and needs no extra artifact.

open as a page

Mockito's @InjectMocks can wire a dependency in more than one way. Which injection strategies does it try, in what order, and how does it choose a constructor when the class under test declares several?

level: middleimportance: must knowfreq 62%

basics

~20 s

Mockito tries constructor injection first, then property setter injection, then direct field injection, and stops at the first strategy that works — it does not combine them. For constructors it picks the one with the most parameters and resolves each argument by type, passing null for anything it cannot match.

open as a page

When stubbing a Mockito spy, why can when(spy.loadData()).thenReturn(...) be dangerous, and what should you write instead?

level: middleimportance: must knowfreq 58%

basics

~20 s

Because when(spy.loadData()) has to evaluate spy.loadData() to record the stub, and on a spy that runs the real method — with its side effects, cost, or exceptions. Use doReturn(value).when(spy).loadData(), which registers the stub without ever invoking the real method.

open as a page

A test that uses Mockito's @InjectMocks fails with a NullPointerException because one dependency inside the object under test is null, even though the test class declares a matching @Mock field for it. How do you diagnose and fix that?

level: seniorimportance: must knowfreq 55%

basics

~20 s

Injection failures are silent, so work through the causes: the wide constructor won and setter/field injection never ran; the field is final or static; two dependencies share a type and names do not match; or annotations were never processed. The reliable fix is to construct the object explicitly in the test.

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

In a Mockito test, is a test-class field annotated @Spy injected into the object annotated @InjectMocks? And what does it mean to put both @Spy and @InjectMocks on the same field?

level: middleimportance: should knowfreq 40%

basics

~20 s

Yes — @Spy fields join @Mock fields in the injection pool, so a spied collaborator is injected like any mock. Putting @Spy and @InjectMocks on the same field means the object under test is itself wrapped as a spy after its dependencies are injected, making it a partial mock.

open as a page

How does Mockito create the object when you annotate a test-class field with @Spy, and what kinds of classes or methods will that fail on?

level: middleimportance: should knowfreq 40%

basics

~20 s

If you initialize the field yourself, Mockito spies that instance. If you leave it uninitialized, Mockito instantiates the type using a no-arg constructor (private is fine) and spies that. It fails for interfaces and abstract types with no instance, and for types with only argument-taking constructors — initialize those inline.

open as a page

MockitoAnnotations.openMocks(this) returns an AutoCloseable. What does closing it do, what goes wrong in a large suite if you never close it, and how does it differ from the older initMocks call?

level: seniorimportance: should knowfreq 30%

basics

~20 s

Closing ends that mocking session and releases the mocks Mockito is holding. With the inline mock maker every mock is kept in a global registry until released, so never closing means mocks and everything they captured stay reachable across thousands of tests — growing memory, sometimes to OutOfMemoryError. initMocks returned nothing, which is why it was deprecated in favour of openMocks.

open as a page

Mockito's spy(realObject) does not wrap the instance you hand it. Explain what it actually builds, and what that means for state changes made through the spy and for calls the real code makes on itself.

level: seniorimportance: should knowfreq 42%

basics

~20 s

Mockito creates a new instrumented instance of the same class and shallow-copies the original's fields into it. Mutations through the spy therefore never reach the original object. Real method bodies execute on the spy, so this is the spy and self-calls are intercepted and stubbable.

open as a page

Some teams forbid Mockito's @InjectMocks and require the object under test to be constructed by hand in every test. What is the argument on each side, and how would you decide the rule for a large codebase?

level: principalimportance: should knowfreq 40%

basics

~20 s

@InjectMocks saves boilerplate on wide constructors but resolves wiring reflectively and fails open, so constructor changes rot tests silently. Manual construction costs one line and turns those changes into compile errors. Most large codebases end up preferring explicit construction, with the annotation tolerated for wide legacy constructors.

open as a page

You inherit a Mockito test suite where most tests spy on the class under test and stub out a few of its own methods. What risks does that carry, and when is stubbing a real object's own method still the right call?

level: principalimportance: should knowfreq 36%

basics

~20 s

Every stubbed method is behaviour no longer under test, and the stub encodes the class's internal call graph — so refactoring breaks tests that assert nothing, and stubs drift from the real implementation while staying green. It is still justified for legacy classes you cannot yet restructure and for genuine template-method hooks.

open as a page

In an older Java codebase you find one test class using @RunWith(MockitoJUnitRunner.class) and another declaring a MockitoRule field. What does each do, why would a team pick the rule, and what happens to both when the class is moved to JUnit 5?

level: middleimportance: nice to knowfreq 26%

basics

~20 s

Both are JUnit 4 Mockito integrations: they initialize annotated mocks, validate Mockito usage after each test, and by default detect unused stubbings. The rule exists because a class can have only one runner, so the rule leaves that slot free for another runner. Under JUnit 5 both are ignored silently, leaving mocks null.

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