D
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

AspectTest DoubleBehavior
FakeWorking alternative implementationInMemoryUserRepository instead of DB
StubReturns hardcoded valueswhen(() => repo.getUser()).thenReturn(user)
SpyWraps real object, records callsVerify that save() was called once
MockFully pre-programmed, verifies callsmocktail'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