Test Pyramid Balancing Workflow
Rebalance a test suite toward fast unit tests with a small, targeted set of integration and end-to-end tests.
Objective
Achieve a balanced test distribution that is fast and still catches integration defects.
Environment
- Existing test suites
- Suite duration metrics
- Coverage data
Steps
1. Measure the current distribution
Count tests and total duration by level: unit, integration, and end-to-end.
Expected state: The current imbalance is quantified.
2. Move logic to unit tests
Push assertions down to unit level where the logic can be tested in isolation.
Expected state: Slow end-to-end coverage is partly replaced by fast units.
3. Keep critical end-to-end journeys
Retain a small set of end-to-end tests for real user journeys only.
Expected state: End-to-end tests cover journeys, not every branch.
4. Re-measure and iterate
Confirm the suite is faster while defects are still caught.
Expected state: Faster suite with equivalent defect detection.
Decision points
More end-to-end coverage?
- Add integration and unit instead
- Add more end-to-end
Push coverage down the pyramid; end-to-end tests are slow and brittle.
Delete redundant tests?
- Remove higher-level duplicates
- Keep everything
Remove end-to-end tests whose assertions are covered lower down.
Expected outcome
A balanced suite that runs quickly while still detecting integration and journey defects.
Verification
Confirm suite duration falls, unit tests cover logic, and end-to-end tests remain for critical journeys.
Cleanup
Document the target distribution and review it each quarter.
Overview
Achieve a balanced test distribution that is fast and still catches integration defects.
This workflow is reusable across teams and environments; adapt the commands to your tooling while keeping the sequence and checkpoints intact.
Environment and prerequisites
- Existing test suites
- Suite duration metrics
- Coverage data
Procedure
1. Measure the current distribution
Count tests and total duration by level: unit, integration, and end-to-end.
Expected state: The current imbalance is quantified.
2. Move logic to unit tests
Push assertions down to unit level where the logic can be tested in isolation.
Expected state: Slow end-to-end coverage is partly replaced by fast units.
3. Keep critical end-to-end journeys
Retain a small set of end-to-end tests for real user journeys only.
Expected state: End-to-end tests cover journeys, not every branch.
4. Re-measure and iterate
Confirm the suite is faster while defects are still caught.
Expected state: Faster suite with equivalent defect detection.
# count tests and duration by suite
npx vitest run --reporter=json | jq '[.testResults[].assertionResults[] | .duration] | add'
Verification
Confirm suite duration falls, unit tests cover logic, and end-to-end tests remain for critical journeys.
Decision points
More end-to-end coverage?
- Add integration and unit instead
- Add more end-to-end
Recommendation: Push coverage down the pyramid; end-to-end tests are slow and brittle.
Delete redundant tests?
- Remove higher-level duplicates
- Keep everything
Recommendation: Remove end-to-end tests whose assertions are covered lower down.
Common failures
- Top-heavy suites are slow and flaky.
- Removing coverage without replacing it increases risk.
- Keeping redundant tests wastes CI time.