The Test Pyramid Explained: Layers, Ratios and When to Break the Shape
The test pyramid is a simple picture of how to spread automated tests: many fast ones at the bottom, a few slow ones at the top. Here is what each layer is for, why the shape matters, and when a different shape fits better.
- The pyramid has many unit tests, fewer integration tests and very few end-to-end tests.
- Lower layers are faster, cheaper and more precise. Higher layers give more confidence that the whole system works.
- An upside-down suite, the ice cream cone, is slow, flaky and expensive to maintain.
- Ratios such as 70/20/10 are rough guides. Your architecture should decide the exact shape.
A team automates its regression suite entirely through the browser. At first it feels like real progress, because the tests click through the app just as users do. A year later, the suite takes three hours, fails randomly, and nobody trusts it. The test pyramid is the model that would have warned them.
This article is a strategy guide, so it contains no code that we ran. The ratios quoted are common rules of thumb from industry sources, not measured results.
What is the test pyramid?
The test pyramid is a model for distributing automated tests across levels. Mike Cohn described it in the 2009 book Succeeding with Agile, and Martin Fowler’s writing later made it widely known. The original pyramid had unit tests at the base, service tests in the middle and UI tests at the top. Today the layers are usually called unit, integration and end-to-end.
The shape carries the message. The base is wide because you want many tests there. The top is narrow because you want only a few.
Why a pyramid?
| Property | Unit | Integration | End-to-end |
|---|---|---|---|
| Speed | Milliseconds | Seconds | Seconds to minutes |
| Cost to write and maintain | Low | Medium | High |
| Flakiness risk | Very low | Medium | Higher |
| Failure points to | One function | A boundary between parts | Somewhere in the system |
| Confidence the product works | Narrow | Moderate | Broad |
Each step up the pyramid trades speed and precision for realism. You need some realism, so the top layer exists. But you want most of your checking done where it is fast and where a failure points straight at the cause.
Unit tests: the base
A unit test checks one small piece of logic, such as a function or class, in isolation. It runs in memory, with slow or unpredictable dependencies replaced by test doubles, as covered in our mocking guide. Thousands can run in seconds, so developers run them on every change.
Good candidates are business rules, calculations, validation, parsing and edge cases. A discount rule with ten boundary values should be tested ten times at this level, not ten times through a browser. Our boundary value analysis guide shows how to choose those values.
Integration tests: the middle
Integration tests check that pieces work together: your code with a real database, a service with its message queue, or two services through their API. They catch problems unit tests cannot, such as a wrong SQL query, a missing database column, a serialization mismatch or a misconfigured connection.
API tests usually live here. Testing an endpoint directly, as in our API testing guide, checks real request handling and storage without the cost of driving a UI. Contract tests, which check that a service still meets the expectations of the services that call it, are often placed in this layer too.
The line between unit and integration tests is discussed in more depth in unit vs integration testing.
End-to-end tests: the top
End-to-end tests drive the whole system the way a user does, usually through a browser with a tool such as Playwright, Cypress or Selenium. They prove that the critical journeys work: sign up, log in, search, pay, receive a confirmation.
Keep them for exactly that. A small set of high-value journeys, run on every deployment, gives broad confidence. Trying to test every rule and edge case through the UI is what turns the pyramid upside down. Our end-to-end testing best practices cover keeping this layer stable.
What ratio is right?
A common rule of thumb is roughly 70% unit, 20% integration and 10% end-to-end, and some sources suggest 60-70% at the base. Treat these numbers as a starting point, not a target to enforce. Counting tests is less useful than asking two questions:
- Is each behaviour tested at the lowest level that can catch its bugs?
- Does the suite give fast, trustworthy feedback?
A logic-heavy library might be 95% unit tests. A thin web app that mostly moves data between a form and a database might rightly have more integration tests than unit tests, because that is where its bugs live.
Tip: When an end-to-end test catches a bug, ask whether a lower-level test could have caught it. If so, add that test. Over time, this pushes coverage down the pyramid and keeps the top small.
The ice cream cone anti-pattern
The inverted shape has a name: the ice cream cone. It has a big scoop of manual testing on top, lots of UI automation, a few integration tests and almost no unit tests. It usually grows when automation is added late, by a separate team, through the only interface they can reach: the UI.
The symptoms are familiar. Builds take hours, so feedback arrives a day later. Tests fail for reasons unrelated to the change, such as timing or test data, so people rerun them until they pass. Each UI change breaks dozens of tests. Eventually the team ignores red builds, and the suite stops protecting anything. Many of these failures are the flaky tests problem in disguise.
The testing trophy and honeycomb
The pyramid is not the only model:
- The testing trophy, described by Kent C. Dodds for front-end apps, puts static analysis (type checking and linting) at the base and makes integration tests the largest layer. The reasoning is that component-level integration tests give the best return in UI code.
- The testing honeycomb, described by engineers at Spotify for microservices, also emphasises integration tests, because a small service has little isolated logic and most risk sits in its interactions.
These models do not contradict the pyramid’s core idea. They all say: prefer the fastest test that gives real confidence, and keep slow, broad tests few. They differ on where that sweet spot is for a given architecture.
Where manual testing fits
The pyramid describes automated tests. Human testing still matters, but for different work: exploratory testing, usability, visual judgement and investigating new features. Automate the checks that must be repeated every release, and spend human time where curiosity and judgement find problems that scripts cannot.
Rebalancing an upside-down suite
- Measure. Count tests per layer and record run time and flaky failure rate.
- Stop the growth. New logic gets unit tests first; new UI tests need a clear reason.
- Push down. For each slow UI test, identify the rules it checks and cover them with unit or API tests.
- Prune. Delete UI tests whose checks are now covered lower down. Keep the critical journeys.
- Fix testability. Hard-to-unit-test code is often a design problem, such as logic mixed into UI handlers. Refactoring it makes the pyramid possible.
The pyramid in your CI pipeline
The layers map naturally onto pipeline stages in CI/CD. Run unit tests on every commit, since they finish in seconds or a few minutes. Run integration tests on every pull request. Run the small end-to-end suite before or just after deployment. Fast layers first means most problems are caught within minutes, and the expensive checks run only on changes that have already passed the cheap ones.
Measuring your pyramid’s shape
You cannot rebalance what you cannot see. Tag each test with its layer so you can count and run layers separately. In pytest, for example, register markers and select them on the command line (an illustration, not run for this article):
# pytest.ini
[pytest]
markers =
unit: fast, isolated tests
integration: tests that use a database or service
e2e: browser journeys
# run one layer
pytest -m unit
pytest -m "integration or e2e"
Folder structure works too, such as tests/unit, tests/integration and tests/e2e. Then track a few numbers over time for each layer: how many tests, how long the layer takes, and how often its tests fail without a real bug. Most CI tools report durations, and pytest’s --durations=10 option lists the slowest tests. A layer whose run time keeps climbing, or whose flaky failure rate rises, is where to invest next.
Final thoughts
The test pyramid is a reminder to test each behaviour at the cheapest level that can catch its bugs. Build a broad base of unit tests, a solid middle of integration and API tests, and a thin top of end-to-end journeys. Adjust the exact shape to your architecture, but if your suite looks like an ice cream cone, start pushing tests down today.
Frequently asked questions
What is the test pyramid?
It is a model for automated testing with many unit tests at the base, fewer integration tests in the middle and very few end-to-end tests at the top. Mike Cohn introduced it.
What is a good ratio of unit, integration and E2E tests?
A common guide is about 70% unit, 20% integration and 10% end-to-end. Treat it as a starting point and adjust it to where your system’s risks are.
What is the ice cream cone anti-pattern?
It is an inverted pyramid with mostly manual and UI tests and few unit tests. It leads to slow, flaky and expensive test suites.
What is the testing trophy?
A model for front-end apps that places static analysis at the base and gives integration tests the largest share, arguing they offer the best confidence for the cost.
Is the test pyramid still relevant?
Yes. Its core idea, test at the fastest level that gives real confidence, applies everywhere, even when the exact shape differs by architecture.
Keep learning
Need help with testing, WordPress or SEO?
We help teams ship better software and grow their sites. Tell us what you are working on and we will suggest a clear next step.