maintainable-tests

Installation
SKILL.md

Maintainable tests

Passive: apply silently to any test work, and for small edits mention only the decisions that affect the result. Match the repository's framework and style before importing a pattern, and reuse adequate existing coverage instead of duplicating it.

A developer returning in six months should learn the behaviour, its edge cases and why each important test exists from the tests alone.

Rules

  • Name tests after the behaviour and outcome in domain language (rejects withdrawals that exceed the current balance), not the function (returns false from validateInvite). Parameterised rows get names that say why the row exists.
  • Use concrete, domain-shaped values. Keep intent local: no distant factory or hidden global setup needed to understand a test. When readability and DRY conflict, choose readable duplication; extract a helper only when its name keeps domain meaning.
  • One behaviour per test, with every assertion needed to prove it (result, state change, emitted event).
  • Pick the least powerful double that proves the rule: stub for queries, fake for simple state, spy for an important effect, mock only when the interaction is the behaviour. Mock-heavy tests usually freeze implementation, not behaviour; back adapters with a contract or integration check where they can drift.
  • Make tests deterministic: control time, randomness, locale, timezone, concurrency, persistence at clear boundaries.
  • Hard-to-test code: use existing safe seams first (framework overrides, scoped and reliably restored patches). Refactor production only when necessary, proportionate and authorised; in tests-only work, propose the change instead of making it. Never expose private internals or widen an interface just to make a test pass. Painful tests are often design feedback.
  • Legacy and compatibility behaviour needs a one-line rationale (customer contract, migration, bug reference, or "unknown"). Reuse existing coverage before adding characterisation tests, and change legacy production code in small verified steps.
  • A regression test must fail for the bug it guards. Run it against the defect when feasible.
  • Review order: tests that can pass while behaviour is broken, then brittle implementation coupling, then missing edge cases, then style.

Side effects, configuration, compatibility

Installs
64
GitHub Stars
57
First Seen
Jun 27, 2026