Mocking Strategy & Alternatives (EN)
Mocking is a tool; an overused tool becomes a source of brittle tests. At Tech Lead/Principal level you should be able to explain — and enforce — a consistent policy:
- what we mock
- when we prefer fakes
- when we upgrade to integration/contract tests
1) Definitions (keep teams aligned)
- Stub: returns canned answers; you don’t usually assert how it was called.
- Mock: you assert interactions (calls, counts, arguments).
- Fake: a lightweight working implementation (e.g., in-memory repo).
- Spy: records calls for later assertions.
2) A practical policy that scales
Mock at the boundary
Mock things that are:
- slow (DB/network)
- non-deterministic (clock)
- expensive (crypto)
- outside your control (3rd party APIs)
Prefer fakes for “rich” dependencies
If a dependency has a meaningful behavior model, a fake often produces better tests.
Example: a fake repository with simple invariants.
Avoid mocking value objects and domain rules
If it’s yours and deterministic, test it directly.
3) State-based vs interaction-based testing
- State-based: assert outputs and state changes. More refactor-friendly.
- Interaction-based: assert collaborator calls. Useful when the interaction is the contract.
When is interaction the contract?
- “must publish exactly one message”
- “must call audit logger with these fields”
- “must not call external gateway if validation fails”
4) The over-mocking failure mode
Symptoms:
- tests fail on refactor
- tests mirror internal method calls
- tests are longer than production code
Fix:
- move logic into pure functions/domain layer
- replace mocks with fakes
- assert on observable behavior
5) Async + mocking pitfalls
Common issues:
- forgetting
ReturnsAsync - deadlocks caused by mixing sync-over-async
- not controlling concurrency deterministically
Lead rule:
- if concurrency is essential, consider modeling it with deterministic schedulers or higher-level integration tests.
6) Alternatives to mocks
- In-memory fakes (repos, queues)
- Contract tests for external dependencies
- TestContainers for DB realism
- WireMock-style HTTP stubs (when you own the stub)
7) Interview angle
Be ready to answer:
- “When should you mock?”
- “Why is EF InMemory not a real integration test?”
- “How do you prevent brittle tests?”
A TL answer includes policy + tradeoffs + examples.
8) Review checklist
- [ ] Team has a documented mocking policy.
- [ ] Most unit tests are state-based.
- [ ] Mocks are used at boundaries.
- [ ] Fakes exist for common rich dependencies.
- [ ] Over-mocking is treated as a maintainability smell.