Test Double vs Mock
Fast recall
Quick revision
Core answer
Interview-ready guide
Interview answer
Test double is the general term for any fake object you use in a test.
It's the category. A mock is one specific type of test double. The taxonomy comes from Gerard Meszaros's book on test patterns.
There are five kinds. A dummy is an object you pass to satisfy a method signature but never actually use—like passing null for a parameter the test doesn't care about. A stub returns pre-programmed values.
When you write when repository dot find by I-D then return user, that's a stub. A spy records what methods were called and can optionally delegate to the real object. Mockito's spy method wraps a real instance.
A mock verifies interactions. When you write verify email service dot send, you're using a mock—it asserts the method was called. A fake is a working lightweight implementation, like an in-memory database instead of the real one.
Now, Mockito blurs these lines. What Mockito calls a mock can actually stub and verify, so it's kind of a hybrid. That's pragmatic because most tests need both—stub the return values and verify the calls.
The key distinction is that not every test double verifies interactions, so not everything is technically a mock. Freshers often say mock when they mean any test double, but knowing the taxonomy shows you understand the theory.
In practice, you'd say I'm using a Mockito mock, and everyone knows you mean a test double that can do both stubbing and verification.
Test Double vs Mock
Direct Answer
Test double is the umbrella term for any fake object used in testing; a mock is a specific type of test double that also verifies interactions.
Code Example
// Stub: a canned answer (one kind of test double)
when(repo.findById(1L)).thenReturn(Optional.of(user));
// Mock (verification): assert an interaction (another kind)
verify(emailService).send(user.email());
// Spy: a real object, selectively stubbed
List<String> spy = spy(new ArrayList<>());
doReturn(99).when(spy).size();
// Fake: a lightweight working implementation
Map<Long, User> fakeDb = new HashMap<>();
Common Mistakes & Pitfalls
- Calling everything a mock: Freshers use mock as a synonym for test double, missing that it's a specific type with verification semantics. This leads to confusion when someone says 'don't mock value objects' and they think it means 'don't use any test doubles.' Not knowing spy exists: Beginners overuse full mocks when a spy would be better—testing a class where most methods are real but one needs stubbing. Mockito's
spy()lets you wrap a real instance and selectively stub methods. - Ignoring fakes: Some tests end up with dozens of mock setups when a simple fake would be clearer. Example: mocking every method of a map when you could just use a real HashMap, or mocking a repository with complex state when an in-memory implementation would be more readable.
Check your understanding
Answer these without looking back at the article.
- When would you choose a Fake over a Mock?
- What is the risk of using mocks when a Fake would be more appropriate?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.