Guide

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

StepConceptWhat it answers
1Test levelsPyramid, trophy, or SMURF — which layer for this risk?
2Test doublesStub, fake, or mock — and when to use a real DB?
3Testing behaviorWhat do you assert, and what do you skip?
4Flaky test policyWhat do you do the day CI lies?
5Testing in productionFlags, 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.

Kent C. Dodds – Write tests. Not too many. Mostly integration.Paul Dowman's tech events and interviews
The Practical Test Pyramid (Ham Vocke)The Practical Test Pyramidmartinfowler.com Software Engineering at GoogleAn open-source collection of core C++ library codeabseil.io SMURF: Beyond the Test Pyramid (Google Testing Blog)This article was adapted from a Google Testing on the Toilet (TotT) episode. You can download a printer-friendly version of this TotT epis...Google Testing Blog