Skip to content

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 gate

Fail 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.