Test pyramid strategy
Unit, integration, and E2E test distribution and execution flow.
A healthy test suite catches bugs before production, but not all tests are created equal. Unit tests run in milliseconds and catch logic errors fast. Integration tests verify that components work together. End-to-end tests exercise real workflows but run slow. Most teams write too many E2E tests and too few unit tests, turning CI into a slow, unreliable bottleneck.
This template visualizes the test pyramid strategy: the distribution of test types, the time cost of each level, what each level tests, and the pass/fail decision tree. It's useful for aligning your team on testing discipline and for diagnosing why your CI pipeline is slow or flaky.
When to use this template
- CI/CD strategy review — walk your team through the test distribution: "Do we have enough unit tests? Are we running too many E2E tests?" Annotate each path with real execution times from your CI logs.
- Onboarding new developers — show them where to focus effort. New features should start with unit tests; critical user journeys should have E2E coverage; the middle ground is integration tests.
- Flakiness diagnosis — when your CI is unreliable, mark which test level is causing the most failures. If E2E is the culprit, invest in test isolation and explicit waits. If unit tests are flaky, you likely have hidden dependencies.
How to adapt it
Customize the nodes to your testing stack and add your deployment gates:
- Add parallelization — branch after "Run test suite" to show unit and integration tests running in parallel.
- Add tool names — replace "Unit tests" with "Jest + React Testing Library", "Integration tests" with "Cypress", etc.
- Add coverage thresholds — insert a decision after each test level: "Coverage > 80%?" to show when tests have insufficient breadth.
- Insert security scanning — add a path after "All pass?" to show SAST/dependency scanning before deployment.
Visual edits regenerate clean code, so you can evolve this as your testing strategy matures.
Mermaid code
Copy it anywhere Mermaid is supported — GitHub, Notion, or your docs.
flowchart TD
A[Run test suite] --> B{Test type?}
B -->|Unit tests| C[Fast - seconds]
C --> D[Test functions & classes in isolation]
D --> E{All pass?}
B -->|Integration tests| F[Medium - minutes]
F --> G[Test component interactions & APIs]
G --> E
B -->|E2E tests| H[Slow - 10+ minutes]
H --> I[Test complete user workflows]
I --> E
E -->|No| J[Review failures]
J --> K[Fix code]
K --> A
E -->|Yes| L[Build passes]
L --> M{Deploy?}
M -->|No| N[Hold for review]
M -->|Yes| O[Deploy to staging]
Frequently asked questions
- What is the test pyramid and why does it matter?
- The test pyramid is a strategy for distributing tests across three levels: a wide base of fast unit tests, a middle layer of integration tests, and a small tip of slow end-to-end tests. It matters because it balances feedback speed (unit tests run in seconds) with confidence (E2E tests exercise real workflows). Most teams get this wrong — too many E2E tests, not enough unit coverage — and end up with slow, flaky CI pipelines.
- How many tests should I write at each level?
- A common distribution is 70% unit tests, 20% integration tests, and 10% E2E tests. This is a heuristic, not a law — it depends on your app. A mobile app might skew heavier on E2E. A backend API might have more integration tests. The key is: unit tests should be the bulk, E2E should be the safety net, not the whole pipeline.
- How do I decide when to run which tests?
- In CI, run all unit and integration tests on every commit (they're fast). Run E2E tests on pull requests to main or on a nightly schedule — they're expensive. Developers run unit tests locally before pushing. This keeps CI feedback tight while still catching regression bugs before production.
- What makes a test flaky, and why do E2E tests fail so often?
- E2E tests are flaky because they depend on timing, network, databases, and UI state — all things that vary. Unit tests are flaky when they depend on global state or mock external services inconsistently. Fix E2E flakiness by waiting explicitly for elements, retrying transient failures, and resetting test data before each run. Fix unit-test flakiness by isolating dependencies and using consistent mocks.