Lesson 8 of 9 · 18m
Testing in CI: Gates That Actually Gate
Coverage thresholds, failure budgets, and the CI pipeline structure that keeps the suite honest without becoming a 40-minute bottleneck.
A CI pipeline that takes 40 minutes will be bypassed, and a gate that doesn't gate is decoration. The goal is a suite that's fast enough to run on every PR, thorough enough to catch real regressions, and strict enough that a red build actually blocks merge.
The pipeline shape
lint/typecheck (<1min) → unit tests (<2min) → integration tests (<5min) → e2e (parallelized, <10min) → merge gateFail fast on cheap checks — a lint error shouldn't wait for e2e to run. Parallelize the slow layers (e2e shards across runners, integration tests across databases). A pipeline over 15 minutes needs a serious talk about what's actually running.
Coverage is a floor, not a target
--coverage-fail-under=80 is useful as a floor — a new module at 0% should fail — but chasing 100% produces tests that exercise code without asserting anything. The useful question is per-file or per-feature coverage on the money paths; a global number hides them.
The merge gate rules
- Required checks on the branch protection — a red build blocks merge, full stop.
- No bypass for flaky tests — a rerunnable test is a broken test; fix or quarantine.
- Main must be green always — a red main means someone's PR snuck in broken or a test is environment-dependent. Both are emergencies.
Field notes
- "Works on my machine" means the test isn't isolated — add the env var, seed the data, pin the version.
- CI caching (dependencies, build artifacts) is the difference between a 3-minute and a 15-minute pipeline — invest in it.
- The suite's job is confidence, not completeness — when a test costs more than it earns, delete it.