intermediate

Mocks versus fakes

Use mocks for interaction checks, fakes for realistic lightweight behavior, and avoid doubles that hide broken contracts.

Test doubles replace collaborators. Mocks (via libraries or hand-rolled spies) verify interactions—was `sendEmail` called with the right args? Fakes provide working lightweight implementations—an in-memory repository with real insert/select semantics.

Use mocks when the contract is "call this port"; use fakes when behavior and state matter. Stubs return canned values; spies record calls without strict expectations.

On interviews: refactor a test from over-mocked to fake repository and explain which failures each reveals.

Common pitfalls: mocks that pass when production code never calls the port, fakes that diverge from real DB semantics, and asserting implementation order instead of outcomes.

The trade-off is interaction precision versus behavioral realism—heavy mocking speeds tests but hides integration bugs.

Checklist:

  • Pick double type by what you need to prove.
  • Prefer fakes for persistence and clocks when behavior matters.
  • Reset doubles between tests.