TestingMedium30 XP4 min read
What is the difference between Fake, Stub, Spy, and Mock in testing?
TL;DR: Fake: working lightweight implementation (in-memory database). Stub: returns predefined values, doesn't verify calls. Spy: wraps real object and records calls for verification. Mock: pre-programmed with expected calls and verifications (mocktail/mockito).
Full Answer
| Aspect | Test Double | Behavior |
|---|---|---|
| Fake | Working alternative implementation | InMemoryUserRepository instead of DB |
| Stub | Returns hardcoded values | when(() => repo.getUser()).thenReturn(user) |
| Spy | Wraps real object, records calls | Verify that save() was called once |
| Mock | Fully pre-programmed, verifies calls | mocktail's Mock class |
๐ฏ
Fakes are often better than mocks for complex objects (repositories, services). They exercise the real interface contract without the brittleness of call-by-call verification.
Code Examples
dartAll four test double types
Output
// Fake: works like real repo, in memory // Stub: getUser returns fakeUser โ no call verification // Mock: verify saveUser was called once with fakeUser // Spy: records log() calls, delegates to real Logger
Common Mistakes
- โUsing mocks when fakes are more appropriate โ mocks break when you refactor internal calls
- โNot using when() stubs before calling mock methods โ mocktail throws MissingStubError
Interview Tip
๐ก
Martin Fowler's classic distinction: mocks verify behavior (how), fakes verify state (what). Over-mocking leads to brittle tests. Use fakes for repositories, mocks for verifying side effects (analytics, logging).
#test-doubles#fake#stub#spy#mock#mocktail