advanced 2 min answer

An organisation has a large end-to-end test suite that is slow, flaky and blocks releases. What is the economically correct shape, and how do you get there without losing coverage?

test-pyramidflakye2econtract-testingeconomics
Show the full answer Hide the answer

The costs that are usually uncounted

An end-to-end test is the most expensive test to write, the slowest to run, the most likely to be flaky, and the most expensive to diagnose when it fails — because a failure indicates that something in a long chain is wrong, without indicating what.

The compounding cost is flakiness. At a few percent flake rate across a large suite, a red build is more likely to be noise than a real failure, so the rational response is to re-run — and the team has now trained itself to ignore failures, including the genuine ones. A real regression is re-run, passes for an unrelated reason, and ships.

Flaky tests are worse than no tests, because a missing test is a known gap while a flaky one is false assurance.

The economically correct shape

A small number of end-to-end tests, deliberately chosen, covering the critical user journeys end to end — not comprehensive coverage of every path.

Everything else moves down:

  • Contract tests between services, verified in each provider's own pipeline. This replaces most integration tests: the provider's build fails and names the consumer, with no shared environment and no deployment ordering.
  • Component tests exercising one service with its dependencies virtualised.
  • Unit tests for logic, which are fast, precise and stable.
  • Production techniques — canary, synthetic monitoring, shadowing — for the emergent and environmental behaviour that end-to-end tests were never good at anyway.

What contract tests do not cover, and must be retained for

  • Semantic correctness. A provider returning amounts in cents rather than dollars satisfies every contract and breaks every consumer. The most important limitation and routinely forgotten.
  • Behavioural sequences: "create then read returns what you wrote."
  • Cross-service flows involving asynchronous steps.

These are exactly what the small retained end-to-end set should cover, chosen deliberately rather than inherited.

Getting there without losing coverage

  1. Instrument the suite. Which tests fail, how often, how often the failure was real, how long each takes. Most organisations do not have this and it changes the conversation immediately.
  2. Delete tests that have never caught a real defect and are flaky. This is defensible with data and indefensible without it.
  3. For each remaining test, ask what it verifies and whether a cheaper test could verify it. Push it down.
  4. Introduce contract testing for service boundaries, which absorbs the majority.
  5. Introduce a flake budget with automatic quarantine and a deletion deadlinea quarantined test with no deadline has been deleted without anyone deciding to.
  6. Remove the re-run button on the blocking suite, or the policy has no teeth. Re-runs are what make flakiness survivable and therefore permanent.
  7. Cover the residual gaps with production techniques.

The structural fix underneath

Push logic down to levels that can be tested deterministically. A system that requires end-to-end tests to verify its business rules has those rules distributed across service boundaries — and the test suite's shape is a symptom of the architecture rather than a testing choice.