Functional Testing

The Test Pyramid: How to Balance Unit, Integration and End-to-End Testing

JIN

Oct 26, 2026

Table of contents

Table of contents

    The test pyramid is a model for spreading automated tests across three layers: many fast unit tests at the base, a smaller set of integration tests in the middle, and a few end-to-end tests at the top. The shape exists because tests get slower, flakier, and harder to debug as they cover more of the system. Ratios such as 70/20/10 or 80/15/5 are reasonable first guesses, not targets. The right balance for your product comes from where your risks sit, how fast each layer can give feedback, and how easily your architecture lets you test parts of the system on their own. AI makes tests cheaper to write, but it does not make slow or flaky tests cheaper to run, so the pyramid’s logic still holds.

    In the 2026 Stack Overflow Developer Survey, 58% of respondents said they use AI to write or improve tests, making testing one of the five most common AI tasks in software work. Writing a test has never been cheaper. So the useful question for QA and engineering leaders has shifted from how many tests a team has to where those tests live.

    A suite with thousands of tests in the wrong layers fails in predictable ways. It takes forty minutes to tell a developer what a unit test could have shown in four seconds. It goes red for reasons nobody can reproduce. Google’s own data shows how quickly this adds up: across its test corpus, about 1.5% of all test runs came back flaky, and nearly 16% of its tests showed some level of flakiness. At any real scale, a badly shaped suite costs hours of investigation every week.

    The test pyramid is the oldest and still the most useful answer to the placement question. It is also one of the most misread ideas in testing. This guide treats it as what it really is: a model of the cost of feedback, not a quota. If you need the basic definitions of each test level with code samples, our Unit vs Integration vs E2E Testing guide covers them. Here the focus is balance: how to decide what goes where, how the pyramid compares with the testing trophy, what a sensible mix looks like for a SaaS product, and what changes when AI writes a growing share of your tests.

    What Is the Test Pyramid?

    Mike Cohn introduced the test automation pyramid in his 2009 book Succeeding with Agile. His version had three layers: unit tests at the base, service tests in the middle, and user interface tests at the top. In a companion post, he called the middle layer the forgotten one, because so many organizations went straight from unit tests to UI automation and skipped service testing altogether. Martin Fowler spread the idea further in his Test Pyramid bliki entry, and Ham Vocke’s The Practical Test Pyramid, published on Fowler’s site in 2018, is still the version most engineers learn from.

    Vocke’s advice is to keep two ideas from the pyramid and not get attached to the layer names. Write tests at different levels of detail, and have fewer tests higher up. Everything else is detail.

    What does the shape actually measure?

    The pyramid is a picture of trade-offs. As you move up the layers:

    • Run cost rises: A unit test runs in milliseconds inside one process. An end-to-end test needs a deployed system, a browser, and real network calls.
    • Nondeterminism rises: Every extra process, network hop, and shared environment adds another way for a test to fail without any code change.
    • Diagnosis gets harder: A failing unit test points at a function. A failing end-to-end test points at the whole product.
    • Realism rises too: Only the upper layers prove that the parts work together the way a user will see them.

    That last point is why the pyramid has a top at all. The model doesn’t oppose end-to-end testing. It argues that you should buy each kind of confidence at the lowest price available.

    Is the pyramid about the number of tests?

    Most online guides say yes and quote a fixed ratio, usually 70/20/10. The source of that number was more modest than how it’s repeated. Google’s Testing Blog offered 70/20/10 in 2015 as a reasonable opening estimate. Google’s later book, Software Engineering at Google, describes a rough mix of 80% unit, 15% integration, and 5% end-to-end tests by count, and notes that each team’s balance will vary. SHIFT ASIA’s own testing guide uses 70/20/10 as a starting distribution, and it is a sensible place to start. The mistake is treating any of these numbers as the finish line.

    A more useful way to think about layers: separate a test’s size from its scope. Size describes what a test can do. Small tests run in a single process, medium tests stay on one machine, and large tests can span machines and networks. Scope describes how much code the test actually verifies. A test can be narrow in scope but medium in size, such as a date picker check that needs a real browser. Classifying tests by size gives a team rules it can enforce in CI, which no ratio can offer.

    Unit Tests

    A unit test checks a small piece of behavior, usually a function, class, or module, without starting the rest of the system. The definition sounds settled, but teams disagree on one detail that matters a lot for balance: what happens to the unit’s collaborators. Fowler describes two styles. Solitary unit tests replace every collaborator with a test double. Sociable unit tests let real collaborators run and only stub out slow or external things. Google prefers keeping real dependencies in place wherever practical. Which style your team uses changes how many “unit” tests you need and how brittle they become, so agree on it before you argue about ratios.

    Benefits

    • Fast feedback: Unit tests run in milliseconds, so developers can run thousands of them before every commit without losing focus.
    • Precise failures: When one fails, the cause is usually within a few lines of code, not somewhere across the stack.
    • Pressure toward better design: Code that is hard to unit test often has too many responsibilities or tangled dependencies. Writing the test exposes that early, while it is still cheap to fix.
    • Same result everywhere: Without a database, network, or shared environment, code behaves the same on a laptop and in CI.
    • Living documentation: A clear unit test shows exactly how a rule behaves at its boundaries, which helps the next person who has to change it.

    These benefits explain why the pyramid puts unit tests at the base. They are the cheapest confidence you can buy, and they keep paying back every time the code changes.

    Limitations

    • Blind to seams: A unit test cannot tell you that two services disagree on a field name, that a query fails on the real database, or that a configuration value is wrong in staging.
    • Mocks drift from reality: A mock returns whatever you told it to return. When the real dependency changes, the mock does not. Google’s book admits mock overuse got bad enough internally that some engineers pushed for “no more mocks.”
    • Brittle when tied to implementation: Tests that check how code works, rather than what it produces, break on every refactor. Spotify found this so costly in small services that it kept these “implementation detail tests” only for complex, naturally isolated logic.
    • Coverage can mislead: High coverage proves that lines ran, not that results were checked. Google warns that a coverage target like 80% tends to become a ceiling rather than a floor.

    Most of these limitations come from asking unit tests to do a job that belongs to another layer. A team that tries to prove service-to-service behavior with mocks ends up with a large, fragile base and still misses the bugs that matter most. The fix is rarely more unit tests. It is moving that specific question up one layer.

    Integration Tests

    Integration tests check that pieces built separately work together: your code and its database, your service and a message queue, your frontend and your API. Fowler calls the term murky because some people mean a test of one boundary, while others mean the whole system wired together. That confusion is where many test strategies go wrong, and it is the same gap Cohn noticed in 2009 when teams kept skipping the middle layer.

    It helps to split the middle of the pyramid into three separate jobs:

    • Narrow integration tests: One service talking to one real dependency, such as a database started in a container or a local queue. They catch wrong queries, broken migrations, and serialization mistakes.
    • Contract tests: Both sides of an API agree on a shared contract, and each side is tested against it on its own. They catch breaking changes between teams without needing both systems running at the same time. Fowler’s testing guide covers the pattern in detail.
    • Component or service tests: A whole service is started and tested through its public API, with neighboring services replaced by test doubles. Spotify’s approach is built on this kind of test: start the database, start the service, call the real API, and check the output.

    Lumping these together as “integration” hides how different their costs are. Narrow tests and contract tests are usually fast enough to run on every pull request. Full component tests may not be. Naming them separately lets you budget them separately.

    Why the middle layer matters more than it used to

    When Cohn drew the pyramid, much software was a single application talking to a single database. Today a typical product calls managed cloud services, third-party APIs, and several internal services owned by other teams. More risk now lives at the boundaries than inside functions.

    The result of neglecting this layer has a name: the hourglass, a suite with many unit tests, many end-to-end tests, and very little in between. It describes the end-to-end failures that pile up as problems a medium-scope suite could have caught faster and more easily, and it traces the pattern to code that is too tightly coupled to test in pieces. If your end-to-end suite keeps catching bugs that turn out to be a wrong field mapping or a failed migration, you probably have an hourglass, and the fix is in the middle.

    End-to-End Tests

    End-to-end tests drive the real product the way a user would, usually through a browser or mobile client, against a fully deployed system. They are the only tests that prove the complete path works: the build, configuration, network, identity provider, payment sandbox, and UI working together. Google uses its largest tests mostly to validate configuration rather than code, and often keeps them out of the developer’s daily loop by running them during build and release instead.

    The costs of this layer are well documented. Google’s 2015 post on the subject listed the problems its teams kept running into: nothing runs until the full product is built and deployed, finding the root cause of a failure is slow and painful, and the tests are flaky. Flakiness is the expensive part. Google’s book says that once flakiness approaches 1%, tests start to lose their value, because engineers stop believing the failures. Every end-to-end test you add raises the odds that any given run fails for no real reason.

    What deserves an end-to-end test?

    A useful filter is to ask what would hurt most if it broke in production and couldn’t be caught lower down. That usually leaves a short list:

    • Revenue journeys: Sign-up, checkout, upgrade, renewal.
    • Access paths: Login, single sign-on, password reset, role changes.
    • Cross-service flows: Paths that cross several services and have no lower seam where they can be tested.
    • Configuration-sensitive paths: Anything that depends on environment settings, feature flags, or third-party sandboxes.

    Fowler adds one habit that keeps this layer honest. When a high-level test catches a bug, write a lower-level test that reproduces it before fixing it, so the bug stays covered by fast tests from then on. Teams that follow this find their end-to-end suites stay small without anyone having to police the number.

    Test Pyramid vs Testing Trophy

    The pyramid has rivals, and the best-known is the testing trophy. It has four layers. Static analysis sits at the base: type checkers and linters that catch typos and type errors as you write. Above it is a modest band of unit tests, then a wide band of integration tests, then a thin cap of end-to-end tests.

    Spotify proposed a third shape the same year for microservices: the testing honeycomb. It puts most of the effort into integration tests that exercise a service through its real API, keeps a few tests for complex internal logic, and aims for as few tests as possible that depend on other live services.

    Test pyramid Testing trophy Testing honeycomb
    Proposed by Mike Cohn, 2009 Kent C. Dodds, 2018 Spotify engineering, 2018
    Built for General application development Frontend and full-stack JavaScript Microservices
    Widest layer Unit tests Integration tests Integration tests
    Key idea Cost and speed get worse as scope grows Static analysis is its own layer Each service is treated as the unit
    Main warning Too many slow UI tests Over-mocked unit tests Tests that rely on other live services

    Is the test pyramid outdated?

    Search this topic, and you will find plenty of claims that the pyramid is dead and the trophy replaced it. Look closer, and the models agree on more than they disagree. Both want fast feedback. Both want a thin end-to-end layer. Both warn against suites full of slow UI scripts. Fowler argued in 2021 that much of the pyramid-versus-honeycomb debate is really about wording: what honeycomb and trophy fans call integration tests often looks a lot like what he calls sociable unit tests. In practice, many teams following the trophy and many following the pyramid write similar tests and just draw them differently.

    The trophy does add something real: static analysis as a separate, nearly free layer. TypeScript, linters, and dependency rules catch a whole class of bugs before any test runs. Any modern pyramid should include it at the base.

    The practical takeaway is to stop arguing about shapes and agree on definitions. Write down what a unit test, an integration test, and an end-to-end test may touch in your codebase, using size rules like Google’s if that helps. Once you fix the terms, the right shape for your system tends to follow from its architecture.

    Designing the Right Test Mix

    A balanced suite is designed, not counted. The five steps below work for most teams, whether they are starting from scratch or revising a suite that grew in the wrong direction.

    1. Start from where a failure would hurt

    List the behaviors that would cost the business most if they broke: billing rules, permissions, data validity, the main user journeys, compliance checks. For each one, ask which layer can catch a regression most cheaply and most reliably. This turns the test mix into a risk decision instead of a ratio exercise, and it gives product owners a reason to care.

    2. Push every check to the lowest layer that can catch it

    If a rule can be proven by a unit test, it should not also need a browser. If a database query can be checked against a real database in a container, it does not need a full staging deployment. Every check you move down makes the suite faster and its failures easier to read. The exception is the small set of journeys where only the full system gives real confidence.

    3. Give each layer a time budget

    Ratios are hard to enforce. Time budgets are easy to enforce. A reasonable starting point looks like this:

    • Commit stage: Static checks and unit tests finish in a few minutes on every push.
    • Pull request stage: Integration and contract tests finish in under 15 minutes.
    • Release stage: End-to-end journeys finish in under 30 minutes against a production-like environment.

    When a layer goes over budget, that is your signal to move tests down, split them up, or delete the ones that repeat lower-level coverage.

    4. Measure the shape three ways, not one

    Counting tests per layer tells you very little on its own. Track three views together: the number of tests per layer, the CI minutes each layer uses, and the layer where each escaped defect should have been caught. Add the flake rate for each layer. A suite can look like a pyramid by count while integration tests use most of the pipeline time, and that can be perfectly healthy. A suite where most escaped bugs trace back to missing integration tests isn’t healthy, no matter what the count looks like.

    5. Watch for the warning shapes

    • Ice cream cone: Many end-to-end and manual tests, few unit tests. Google’s book links it to prototypes that were rushed into production without paying down their testing debt.
    • Hourglass: Plenty of unit and end-to-end tests around a hollow middle, usually a sign of tight coupling.
    • Triple coverage: The same business rule checked at all three layers. It feels safe, but it triples maintenance and gives you three failures for one bug.

    None of these steps name a target percentage, and that is on purpose. Teams that manage time budgets, flake rates, and the sources of escaped defects tend to find a sensible shape on their own. Teams that chase a ratio often hit the number and miss the point.

    How AI Changes Test Distribution

    AI is now a normal part of test writing. Alongside the 58% figure for writing or improving tests, the 2026 Stack Overflow survey found that 48% of developers trust AI when they can easily check its answers. That second number matters most here. Tests are how teams validate AI output, which makes the shape of the suite more important, not less.

    DORA’s research points the same way. Its 2025 State of AI-assisted Software Development report found that AI adoption is now positively related to delivery throughput but still negatively related to delivery stability. More code is moving faster, and the test suite is one of the main controls that stops it from moving faster into production incidents.

    AI makes tests cheaper to write, not cheaper to trust

    Playwright now ships three test agents: a planner that explores the app and writes a test plan, a generator that turns the plan into test files, and a healer that runs failing tests and tries to repair them. Tools like these make end-to-end tests much quicker to write and maintain. Some vendors go further and argue that, with authoring costs falling, the top of the pyramid can safely get wider.

    Common sense says otherwise. Writing an end-to-end test was never its main cost. Running it against a full deployment, waiting for it, and investigating when it fails for no clear reason are the main costs, and AI removes none of them. A healer also introduces a new risk: a test repaired to pass may have been patched around a real regression. Playwright’s own documentation says the healer can skip a test when it believes the functionality is broken, so a person still has to check what it decided. Keep the top thin. Use AI to keep those few journeys healthy, and review every repair like any other code change.

    Generated unit tests need something to check against

    Unit tests are where AI generation works best, because they are cheap to run many times and easy to filter. However, do not judge AI-generated tests by how many there are or how much coverage they add. Judge them by whether they catch faults, which is what mutation testing measures. Also watch for a quiet failure mode: when the same model writes the code and the tests from the same prompt, both can share the same misunderstanding. Those tests confirm what the code does, not what it should do. Acceptance criteria written by a person, or derived from the requirement rather than from the code, are what break that loop.

    Where the weight moves

    Put together, AI moves effort between layers more than it changes the overall shape:

    • Unit layer: Grows cheaply in count. The quality gate shifts from coverage to mutation score and human review of what each test actually checks.
    • Integration and contract layer: Becomes more important. AI-assisted changes arrive faster and touch more boundaries, and boundaries are where changes made by different people and tools first collide. This is the layer most teams should be adding to in 2026.
    • End-to-end layer: Stays small in count. AI helps keep it maintained, with a person approving every repair.
    • A new layer for AI features: If your product includes LLM features, you need evaluation suites alongside functional tests because the output changes from run to run.

    The pyramid survives AI for the same reason it survived microservices. It was never really about how hard tests are to write. It was about how much a failing signal costs to run, trust, and act on, and AI only changes the first of those. The same principle shapes SHIFT ASIA’s own AI-driven testing framework, which applies AI from test case design through execution while keeping people accountable for what each test is meant to prove.

    Find Out What Shape Your Test Suite Really Is

    Most teams know their test count. Far fewer know where their pipeline time, flaky failures, and escaped defects actually come from.

    Those three numbers usually say more about your test balance than any ratio. SHIFT ASIA’s test automation engineers work with product teams to measure them layer by layer, move checks down to where they run fastest, build out the integration and contract layer most suites are missing, and keep end-to-end coverage focused on the journeys that pay the bills. Our teams pair SHIFT Inc.’s Japan-standard QA discipline with the scale and cost of Vietnam-based delivery, and use AI throughout test design and execution, with human review on every test that matters.

    Talk to our test automation team →


    Frequently Asked Questions

     

    The test pyramid is a model for spreading automated tests across layers: many fast unit tests at the base, fewer integration tests in the middle, and a small number of end-to-end tests at the top. Mike Cohn introduced it in 2009. It reflects the fact that broader tests are slower, flakier, and harder to debug.

    There is no universal ratio. Google has offered 70/20/10 as a first estimate and describes a rough 80/15/5 mix for its own code, while noting that each team’s mix differs. A better guide is to push each check to the lowest layer that can catch it and to give each layer a time budget.

    Yes. Its core idea, that faster and cheaper feedback should carry most of the load, still holds. What has changed is the middle layer's weight. Microservices, third-party APIs, and AI-assisted code put more risk at system boundaries, so most teams need stronger integration and contract testing than the original pyramid suggested.

    The pyramid makes unit tests the widest layer. The testing trophy, proposed by Kent C. Dodds in 2018, adds static analysis as a base layer and makes integration tests the widest layer. Much of the difference comes from how each model defines a unit test, so in practice both often lead to similar suites.

    Usually fewer than teams expect: enough to cover the journeys that matter most, such as sign-up, login, upgrade, and key data flows. Many SaaS products can protect those with 10 to a few dozen journeys, as long as unit and integration tests cover the underlying rules.

    Contract tests sit in the middle layer next to integration tests. They verify that two systems agree on an API contract without running both at once, making them faster and more stable than end-to-end tests for catching breaking changes between services or teams.

    AI lowers the cost of writing tests at every layer, but it does not lower the cost of running slow tests or investigating flaky ones, so the shape still holds. AI-generated unit tests by whether they catch faults, and have a person review AI-repaired end-to-end tests before merging.

    Share this article

    ContactContact

    Stay in touch with Us

    What our Clients are saying

    • We asked Shift Asia for a skillful Ruby resource to work with our team in a big and long-term project in Fintech. And we're happy with provided resource on technical skill, performance, communication, and attitude. Beside that, the customer service is also a good point that should be mentioned.

      FPT Software

    • Quick turnaround, SHIFT ASIA supplied us with the resources and solutions needed to develop a feature for a file management functionality. Also, great partnership as they accommodated our requirements on the testing as well to make sure we have zero defect before launching it.

      Jienie Lab ASIA

    • Their comprehensive test cases and efficient system updates impressed us the most. Security concerns were solved, system update and quality assurance service improved the platform and its performance.

      XENON HOLDINGS