What is the difference between a mock, a stub, a fake and a spy?

Unit Testing & TDD Test Doubles Intermediate 2–3 Yrs3–5 Yrs Conceptual 1 min read

Quick Answer

All are test doubles. A stub returns canned answers to calls. A mock also has expectations you verify (“was Send called once with this argument?”). A fake is a real working implementation that's just not production-suitable (an in-memory repository). A spy records calls for later inspection. A dummy is a placeholder that's never used.

They're all test doubles, differing in what they do. A stub just returns a fixed answer when you call it. A mock does that too, but you also set expectations on it and verify them — “assert that SendEmail was called exactly once.” A fake is an actual working implementation that isn't fit for production, like an in-memory list standing in for a database. A spy records what happened for you to check afterwards. My preference is to verify state — use a stub or fake and check the outcome — and only verify behaviour with a mock when the interaction itself is the thing I care about, like an email being sent, because behaviour verification makes tests fragile.

  • State verification (preferred) — use stubs/fakes and assert on the result or the state afterwards.
  • Behaviour verification — use mocks and assert on the interactions; useful when the effect is the interaction (an email was sent) but over-use makes tests brittle and coupled to implementation.
  • Moq/NSubstitute blur the lines — a single object can act as a stub (Setup().Returns()) and a mock (Verify()).
  • Prefer a real object > a fake > a stub > a mock, in that order, for robustness.