Tests in the pipeline

Run the suite on every change, fast enough that nobody is tempted to skip it.

15of 16
≈ 12Min read
5Parts

What the pipeline is for

A test suite that runs only on the machine of whoever remembers is not a safety net. Continuous integration is the arrangement where every change is proved against the whole suite before it lands — and the value comes entirely from it being automatic, fast and trusted.

Fast, because a twenty-minute pipeline changes behaviour: people batch changes, stop waiting, and merge on a hope. Trusted, because a suite that fails at random teaches everybody to ignore red.

The order to run things in

Failing at step two costs a developer ninety seconds; failing at step six costs ten minutes. Order by cost and by probability, and let the slow stages run in parallel with each other where they do not depend on one another.

cheapest and most likely to fail, first
1. install (cached)        seconds
2. lint + type check       seconds      — catches the typo before the tests do
3. unit tests              seconds
4. integration tests       a minute or two
5. build                   a minute
6. end-to-end              a few minutes
7. deploy

Making it fast

  • Cache the install. A lockfile hash is the cache key; this is usually the single biggest win.
  • Parallelise by time, not by count. Splitting 400 tests into four groups of 100 gives four unequal workers; splitting by recorded duration gives four equal ones.
  • Run only what changed, in a large repository — with a periodic full run, because the dependency graph lies eventually.
  • Keep the slow ones out of the fast path: end-to-end on merge and nightly, not on every push to a branch.

What should fail the build

SignalBlocks?
A failing testyes — that is the point
A lint erroryes, if it is a rule you agreed on; format automatically instead of complaining
Coverage below the ratchetyes, as a floor — never as a target
A new flaky testit should be visible, and owned; blocking is a team decision
A known-quarantined testno — but the list has a name and a date against each one
A quiet retry is how a suite rots

If the pipeline retries failures silently, a test that fails half the time looks green and the production race behind it never gets found. Retry if you must, and report the retry count as a metric somebody watches.

The environment

Pin the runtime version, fix TZ=UTC and the locale, seed anything random, and make the database per-run rather than shared. "It passes locally" is nearly always one of those four differences — and every one of them is a line of configuration.

Practice