Skip to content
Back to Quality Assurance

Test Pyramid

Balance the test suite: many fast unit tests, fewer integration, very few end-to-end.

Why

The test pyramid is a heuristic for allocating test effort by speed and confidence. The base — many unit tests — runs in seconds, catches most regressions, and gives precise failure locations. The middle — integration tests — runs in minutes and catches seam bugs. The tip — a few E2E tests — runs in tens of minutes and catches journey-breaking changes but is flaky and slow. A team that inverts the pyramid (few unit tests, many E2E) ends up with a 40-minute suite that is flaky, hard to debug, and that nobody runs locally. The pyramid keeps the fast feedback loop fast and reserves the slow, expensive tests for the few journeys that warrant them.

When

Apply the pyramid as a suite-shape target from the start of the project, and audit the actual shape periodically. If the E2E suite is growing faster than the unit suite, rebalance before the feedback loop degrades.

How

1. Measure the current suite shape
   - Count tests by type: unit, integration, e2e
   - Measure run time per type: unit (<10s), integration (<5min), e2e (<20min)
   - Plot as a pyramid: if e2e > integration > unit, you are inverted

2. Set target proportions (classic pyramid)
   - Unit: 70% of tests, <10s total run time
   - Integration: 20% of tests, <5min total
   - E2E: 10% of tests (3-15 tests), <20min total
   - Adjust for your context: a UI-heavy app may have more E2E, a library almost none

3. Push tests down the pyramid whenever possible
   - An E2E test that checks a form validation → move to a unit test of the validator
   - An integration test that checks a pure transform → move to a unit test
   - The lower the test sits, the faster and more precise the feedback

4. Gate the suite shape in CI
   - Fail if e2e count grows beyond a threshold (e.g. 20) without review
   - Warn if unit coverage drops below 60% on changed files
   - Track suite run time as a metric; investigate if it grows > 20% per quarter

5. Re-audit quarterly and rebalance
   - Identify tests that can be pushed down (an E2E that tests logic, not a journey)
   - Delete tests that guard nothing (the code they tested was removed)
   - Keep the fast loop fast — that is the pyramid's whole point

Example

# Audit script: count tests by type and measure run time
# scripts/audit-pyramid.sh
echo "=== Test Pyramid Audit ==="
echo "Unit tests:       $(find src -name '*.test.ts' | wc -l)"
echo "Integration tests:$(find tests/integration -name '*.test.ts' | wc -l)"
echo "E2E tests:        $(find e2e -name '*.spec.ts' | wc -l)"

echo ""
echo "=== Run times ==="
time vitest run --reporter=dot 2>&1 | tail -1   # unit
time vitest run --config vitest.integration.ts 2>&1 | tail -1  # integration
time npx playwright test 2>&1 | tail -1  # e2e

# Sample output:
# Unit tests:       342
# Integration tests: 48
# E2E tests:         12
# Ratio: 85% / 12% / 3% — healthy pyramid, fast feedback loop intact.

# Inverted pyramid (bad):
# Unit tests:        18
# Integration tests: 24
# E2E tests:        156
# Ratio: 9% / 12% / 79% — 40-min suite, nobody runs it locally, regressions slip in.

Common Problems

  • ⚠An inverted pyramid (many E2E, few unit tests) gives a 40-minute suite that is flaky and imprecise — when an E2E fails, the root cause could be anywhere in the stack, and debugging takes hours instead of seconds.
  • ⚠A "ice cream cone" (many manual tests, some E2E, few unit) relies on humans to catch regressions, which does not scale — the team grows, the test surface grows, and manual coverage inevitably falls behind.
  • ⚠Treating the pyramid as a rigid rule rather than a heuristic leads to forcing tests into the wrong layer — a thin UI library may legitimately have mostly E2E/visual tests, and that is fine.
  • ⚠Measuring only test count, not run time, hides the real problem — 100 unit tests that take 2 minutes each (because they hit a database) are worse than 20 E2E tests that take 30 seconds each.

Best Practices

  • ✓Track both test count and run time per layer — the pyramid is about fast feedback, so a 70/20/10 split where the 70% takes 5 minutes is not a healthy pyramid.
  • ✓Whenever a test is slow or flaky, ask "can this be pushed down a layer?" — most E2E tests of logic can become unit tests of the same logic with the UI stripped away.
  • ✓Audit the pyramid shape quarterly and set a budget: e.g. "unit suite must stay under 10s, E2E under 20 tests" — enforce it in CI with a warning or failure when exceeded.
  • ✓Adapt the pyramid to your context: a backend microservice may have a diamond shape (many integration, some unit, few E2E), and that is correct for its seam-heavy architecture.