Craft of code
Testing strategy
What to test, at which level, and how to keep a suite fast, reliable, and worth the maintenance — from pyramid trade-offs to production safety nets.
Tests exist to give you confidence to change code. Everything else — documentation, design feedback, onboarding — is a side effect. A suite that is slow, flaky, or coupled to implementation details fails that purpose: people stop running it, start skipping CI, and ship scared.
A useful strategy answers three questions for every change: what behavior must not regress, which test level buys the most confidence per minute, and what will we do when the suite lies?
Good tests do three jobs. Regression safety — you can refactor a payment path and know the total still computes. Executable specs — a new teammate reads refunds_when_stripe_event_is_duplicate and learns the rule. Design feedback — code that is hard to test is often hard to use.
SDE2s leave a change safer than they found it: tests that fail for the right reason, run in CI, and do not flake. In code review, ask "what would break if this assertion were deleted?" In interviews, talk about risk-based testing and flake policy, not "we aim for 90% coverage."
A healthy CI pipeline usually stages a fast gate (unit, lint, types in a few minutes), then sharded integration for the default PR check, then nightly E2E or mutation on hot packages. Document pnpm test path/to/file so people run the smallest subset before they push. When you talk to PMs, translate: a missing invoicing integration is a Sev-2 risk, and a flake that burns retrigger hours is capacity, not polish.
Concepts in this section
| Step | Concept | What it answers |
|---|---|---|
| 1 | Test levels | Pyramid, trophy, or SMURF — which layer for this risk? |
| 2 | Test doubles | Stub, fake, or mock — and when to use a real DB? |
| 3 | Testing behavior | What do you assert, and what do you skip? |
| 4 | Flaky test policy | What do you do the day CI lies? |
| 5 | Testing in production | Flags, canaries, and synthetics for what the suite cannot invent |
Common mistakes
- Testing implementation because it is easy, skipping boundaries because they need fixtures.
- One giant E2E suite as the only safety net.
- Mocking the database in every service test, then discovering SQL bugs in production.
- Celebrating coverage % while checkout has no integration test.
- Leaving flaky tests red for weeks until nobody trusts CI.
Key takeaways
- Tests buy confidence to change. Optimize for signal per minute, not coverage %.
- Assert behavior at boundaries. Prefer fakes and real dependencies over deep mock webs.
- Flakes are cultural debt — quarantine and fix, do not normalize retries.
- Canaries, flags, and synthetics extend confidence into production.
- Stage CI into a fast gate and a deeper suite. Keep local commands short.
Further learning
Kent C. Dodds' talk compresses the trophy mindset: write tests, not too many, mostly integration.

Related
Writing code others can maintain
Managing complexity with deep modules, clear naming, honest comments, consistent style, and error strategies that shrink the blast radius of change.
Continuous integration and the software supply chain
Fast, trustworthy pipelines - build, test, artifact, scan and sign - plus DORA metrics and supply-chain controls that keep trunk green.
Code review
Author small, reviewable PRs and give reviews that improve both the code and the author — design first, tone that teaches, turnaround that unblocks.