Skip to main content

Testing strategy

Test types​

TypeBest forAvoid when
UnitPure domain logic, validation, calculations, branching rulesBehavior depends on the DB, framework, network, or real wiring
IntegrationRepositories, framework, DI wiring, adaptersA unit test proves the same thing
ContractAPI schemas, event payloads, provider/consumer expectationsNo stable external contract exists
API / smokeFull request path, health, deployment wiringIt needs destructive calls or production credentials
CharacterizationLegacy behavior before a refactorThe current behavior is known to be wrong
RegressionA fixed bug with a known failing scenarioThe test restates implementation details

Keep many fast unit tests, fewer integration tests, and a small number of end-to-end tests.

Quality rules​

  • Test behavior, not private methods or internal state.
  • Name tests as specifications: returns validation error when email is missing.
  • Take expected values from examples, specs, or literals, not by re-running the code under test.
  • One behavior per test.
  • Mock only at system boundaries: network, time, randomness, filesystem, external services. Do not mock internal collaborators by default.
  • Use builders or factories for complex domain objects; keep setup local unless a shared fixture removes real repetition.
  • Remove dependence on wall-clock time, random order, shared global state, and test execution order.

Bugs​

Reproduce a bug with a failing test first when feasible, then fix it. The test stays as the regression guard.

Guardrails​

  • Never delete, skip, or weaken a test just to get a green run.
  • Never disable lint, type checks, hooks, or coverage gates to get green output.
  • Quarantine a flaky test only with a written reason and a follow-up, not as a default fix.
  • Do not claim a check passed unless it was run.