Fake Object vs Mock
Fast recall
Quick revision
Core answer
Map-backed repository that really stores and retrieves values. A Mockito mock is configured per test with stubs and can record interactions for verification. A fake is useful when state should behave consistently across several calls; a mock is useful when a test needs controlled replies or must check a boundary interaction.Interview-ready guide
Interview answer
A fake is a small working implementation of a dependency.
For example, a Map-backed repository can assign an ID, store a user, and return it from a later lookup. )`. I prefer a fake when a workflow needs consistent state across several calls, such as saving and then checking for a duplicate.
I prefer a mock when I need one controlled response or want to prove an observable boundary interaction, such as sending one email.
The trade-off is that a fake can drift from the production implementation, so shared contract tests are useful. I would not treat H2 as proof that production PostgreSQL behavior is correct; H2 is a separate real database with its own behavior.
Fake Object vs Mock
Direct Answer
A fake is a small working implementation used in tests, such as a Map-backed repository that really stores and retrieves values. A Mockito mock is configured per test with stubs and can record interactions for verification. A fake is useful when state should behave consistently across several calls; a mock is useful when a test needs controlled replies or must check a boundary interaction.
Code Example
// Fake: real implementation using HashMap
class FakeUserRepository implements UserRepository {
private final Map<Long, User> storage = new HashMap<>();
private Long nextId = 1L;
public User save(User user) {
if (user.id() == null) {
user = new User(nextId++, user.name(), user.email());
}
storage.put(user.id(), user); // Real storage logic
return user;
}
public Optional<User> findById(Long id) {
return Optional.ofNullable(storage.get(id)); // Real lookup
}
}
// Mock: Mockito-generated hollow shell
@Test
void testWithMock() {
var mockRepo = mock(UserRepository.class);
var user = new User(1L, "Alice", "alice@example.com");
when(mockRepo.save(any())).thenReturn(user); // Programmed response
var result = mockRepo.save(user);
verify(mockRepo).save(user); // Only verifies interaction, no real storage
}
Common Mistakes & Pitfalls
- Calling an alternative database a perfect fake: H2 is a real database with its own dialect; passing tests do not prove PostgreSQL or MySQL behavior.
- Copying production complexity: a fake should stay small and focused on the relevant contract.
- Letting a fake drift: run shared contract tests against the fake and real implementation where practical.
- Over-scripting a mock: a long sequence of stateful stubs may be clearer as a small fake.
- Verifying every call: verify only interactions that are observable requirements.
Check your understanding
Answer these without looking back at the article.
- When would you write a Fake instead of using Mockito?
- What are the maintenance challenges of keeping Fakes in sync with the real implementation?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.