In Mockito, what is the difference between a mock and a spy?
answer
- Mock = no real code, returns defaults
- Spy = real object, real code unless stubbed
- Partial mocking = override only some methods
- Stub spies with doReturn().when(), not when().thenReturn()
- Mock to isolate, spy to keep most real behavior
basics
~20 sA mock is a fake object with no real behavior; every method returns a default (null, 0, false) until you stub it. A spy wraps a real object and runs its real code unless you stub a specific method.
solid answer
~40 sA Mockito mock is a completely fake stand-in: it has no real implementation, so every method call returns a type-based default (null for objects, 0 for ints, false for booleans, empty collections) until you stub it with when(...).thenReturn(...). A spy, created with Mockito.spy(realObject) or @Spy, wraps a real instance and delegates to the actual methods by default, recording the calls. You only override the methods you explicitly stub, which is called partial mocking. Use a mock when you want to fully control and isolate a dependency; use a spy when you want most of the real behavior but need to override or verify a few methods. A common gotcha: stub spies with doReturn(...).when(spy).method() rather than when(spy.method()).thenReturn(...), because the latter actually calls the real method first.
code
java · 14 lines// Mock: no real behavior, returns null/0/false until stubbed
List<String> mockList = Mockito.mock(List.class);
System.out.println(mockList.size()); // 0 (default, real code never runs)
when(mockList.size()).thenReturn(5);
System.out.println(mockList.size()); // 5 (stubbed)
// Spy: wraps a REAL ArrayList, runs real methods by default
List<String> spyList = Mockito.spy(new ArrayList<>());
spyList.add("a"); // real add runs
System.out.println(spyList.size()); // 1 (real behavior)
// Safe spy stubbing: doReturn(...).when(...) never calls the real method
doReturn(100).when(spyList).size();
System.out.println(spyList.size()); // 100 (overridden)go deeper
States the one-line difference: mock = fake/no real behavior/returns defaults; spy = real object running real code unless stubbed. Knows mock() vs spy().
Explains partial mocking, when to pick each, and recognizes the doReturn().when() safety rule for spies even if shaky on why.
Articulates WHY when(spy.foo()) calls the real method (argument-evaluation order), names default-value semantics precisely, and advises mock-by-default with spies as a smell to investigate.
Frames it against the xUnit double taxonomy, discusses testability/design implications (over-reliance on spies signaling SRP violations or untestable legacy code), and sets team conventions on when partial mocking is acceptable.
## What problem mocking solves In unit testing you isolate the **class under test** from its **collaborators** (dependencies it talks to: a repository, an HTTP client, a clock). Instead of using the real collaborator you substitute a **test double** — a stand-in object you control. Mockito is the most popular Java library for creating these doubles. The two main kinds it produces are **mocks** and **spies**. ## Mock — a fully fake object A **mock** is created with `Mockito.mock(SomeClass.class)` or the `@Mock` annotation. Mockito generates a subclass/proxy of the type at runtime where **none of the real code runs**. Every method is replaced. Until you tell it otherwise, each method returns a **default value** based on its return type: - object types → `null` - `int`/`long`/`double` etc. → `0` - `boolean` → `false` - collections (`List`, `Set`, `Map`) → empty collection (a Mockito convenience) You then **stub** behavior — define what a method should return — with `when(mock.foo()).thenReturn(value)`. You **verify** interactions with `verify(mock).foo()`. The key idea: a mock has **no real behavior at all**, so the test is fully isolated and deterministic. ## Spy — a wrapper over a real object A **spy** is created with `Mockito.spy(realObject)` or `@Spy`. A spy holds a **real instance** and, by default, **delegates every call to the real method** — the actual code executes. The spy additionally **records** every call so you can `verify(...)` it, and lets you **selectively override** individual methods. Overriding only some methods of an otherwise-real object is called **partial mocking**. So the default behavior is the headline difference: | | Mock | Spy | |---|---|---| | Underlying object | none (all fake) | a real instance | | Default method behavior | returns type default | runs the real method | | You stub… | the methods you need | only the methods you want to override | | Typical use | isolate a dependency | keep real behavior, tweak/verify a bit | ## The `doReturn().when()` gotcha With a **mock**, both stubbing styles work: ```java when(mock.getValue()).thenReturn(42); // fine on a mock ``` With a **spy**, that same line is dangerous. Because Java evaluates arguments before calling a method, `mock.getValue()` (here a spy) is **actually invoked for real** before `when(...)` ever sees it. If the real method throws (e.g. hits a null field or a DB), your stubbing line blows up. The safe form is: ```java doReturn(42).when(spy).getValue(); // does NOT call the real method ``` Here `when(spy)` returns a stubbing proxy and `.getValue()` is intercepted, not executed. Rule of thumb: **always stub spies (and any method with risky side effects) with `doReturn(...).when(...)`.** ## When to choose which - **Mock** by default — it gives the cleanest isolation and forces you to think about exactly which interactions matter. - **Spy** only when you genuinely need most of a class's real behavior but want to stub/verify a slice of it — e.g. testing a method on a class while overriding one helper it calls. Heavy reliance on spies often signals a class doing too much; consider splitting it instead. ## Related notions Mockito's `mock`/`spy` are *technical* tools. The classic xUnit vocabulary (Gerard Meszaros) distinguishes **dummy, fake, stub, spy, mock** by *role*. Mockito blurs these — a Mockito "mock" can act as a stub (canned answers) or a mock (verifies interactions). Don't over-index on the textbook taxonomy in interviews; explain Mockito's two concrete behaviors clearly.
- Why does when(spy.foo()).thenReturn(x) misbehave but the same works on a mock?Java evaluates spy.foo() before when(...) sees it, so on a spy the real foo() actually runs (and may throw). On a mock there is no real method, so nothing harmful happens. Use doReturn(x).when(spy).foo() to avoid invoking the real method.
- If you create a spy from new ArrayList<>() and never stub anything, what does size() return after two real adds?2 — a spy delegates to the real object, so the real add and size run.
A mock is a cardboard cutout of a person — looks like them but does nothing until you script it. A spy is the real person wearing a wire: they act normally, you record everything, and you can occasionally feed them a line to say.
saying these in an interview costs you the question
- Saying a spy is 'just a mock with a real name' — the defining difference is that a spy runs real code by default while a mock never does.
- Claiming when().thenReturn() never works on spies — it works for safe methods, it's just unsafe when the real method has side effects or throws.
- Thinking a mock returns the real object's values — a fresh mock returns type defaults, not real behavior.
- Believing a spy stubs all methods automatically — only the ones you explicitly override are changed.