Goal: fast, honest tests that isolate the unit without faking its behavior.
Use for:
- isolating a unit from slow or external dependencies
- deciding what to fake versus exercise for real
- fixing brittle tests coupled to implementation
Workflow:
- Identify the true external boundary (network, clock, filesystem).
- Mock or stub only that boundary, not internal collaborators.
- Use the lightest double that works: stub, fake, or mock.
- Assert on observable behavior, not on every internal call.
- Keep doubles in sync with the real contract.
- Verify the integration with the real dependency elsewhere.
Doubles:
- stub: returns canned data
- fake: a working lightweight implementation
- mock: asserts interactions occurred
- spy: records calls for later inspection
Rules:
- do not mock the thing you are testing
- prefer real collaborators when they are fast and deterministic
- avoid asserting on internal call sequences
- verify mocked contracts against reality in integration tests