QASenior

End-to-end testing

End-to-end testing walks a business process through the assembled system from start to finish, the way a customer would, in conditions close to production. The page opens with one shop’s whole suite — twelve journeys, the seam only each one proves, and what is real and what is replaced — then covers what no lower level can prove, the shapes a portfolio takes, what a red journey costs, how to choose journeys and keep them trustworthy, and three failures where a test stopped one step short.

It proves
The parts hold together
Cost per case
Highest of any test
Right number
Small, not zero

One shop’s end-to-end suite on one screen — twelve journeys, the seam each proves, and what is real

Nobody opens a page about end-to-end testing for the definition. They open it because a suite of four hundred browser tests takes an hour and fails every other run, or because someone asked how many such tests a team should have. Below is the whole end-to-end suite of the online shop whose smoke gate and regression suite the two neighbouring pages list. It has twelve journeys. Each row names the seam only that journey proves — a place where two real parts of the system meet and no lower test can reach — and says what is real and what is replaced. Later sections cite the journeys by number.

#JourneyThe seam only it provesReal, and replacedTime
1Search “blue jumper”, open SKU 30417, add it, pay with the test card, get an order numberFront end → checkout → payments → orders → queue → warehouse: the order arrives with every line and amount right (regression row 16)Everything of the shop’s; the payment provider’s sandbox; the warehouse’s test endpoint90 s
2Sign up, confirm the email, sign in, reload — still signed in. In Chromium and in WebKitThe session cookie through the CDN, the front end and accounts, in a real browser engine (regression row 3)Real; the email provider’s test mode delivers to a test inbox2 × 60 s
3Reset a forgotten password from the emailed linkA link built by accounts, carried by email, opened through the CDN’s redirect, accepted onceReal; test inbox45 s
4Apply SPRING10, change the quantity, payThe total on the screen is the amount the payment provider is asked to chargeReal; sandbox70 s
5Pay with a card that needs 3-D Secure: out to the bank’s check and backThe redirect out of the shop and back into the same session and the same basketReal; the sandbox’s challenge page80 s
6A card is declined; pay again with a second cardThe basket survives the decline, and exactly one order exists afterwardsReal; the sandbox’s decline card75 s
7Ask the order assistant “where is my order” about an order the journey has just placedChat widget → assistant → get_order → orders, and the returned status on the screenReal tools; the model’s replies replayed from a recording, as on Testing LLM products40 s
8Start a return within 30 days; the returns label arrives by emailReturns → orders → email, with the label attached and readableReal; the carrier’s label service replaced by a stub, whose shape a contract test checks60 s
9The warehouse confirms the return arrived; the refund landsA webhook from the warehouse → refund → payments → email, with the amount that was paidReal; the test harness sends the warehouse’s webhook90 s
10Change the delivery address after ordering, before dispatchThe new address reaches the warehouse before the order is pickedReal50 s
11Check out as a guest, then create an account from the confirmation pageAn anonymous basket and order become a customer’s, and appear in their order historyReal70 s
12A support agent refunds a damaged item in the back officeThe back office and the shop share orders and payments; an agent can refund, but cannot change a priceReal; the staff sign-in replaced by a test identity60 s
Each of the twelve journeys exists for one seam — a place where two real parts of the shop meet in the deployed system and no lower test can reach — and the green numbers put each journey on its seam, as the table’s third column names it. The cookie in a real browser engine (2), the emailed link through the CDN (3), the amount the payment provider is asked to charge (4) and the trip out to 3-D Secure and back (5), exactly one order after a declined card (6), the order travelling through the queue to the warehouse (1, 10), the assistant’s tool call into orders (7), the warehouse’s confirmation that starts a refund (9), the returns label (8), a guest order becoming a customer’s (11) and the back office’s limits (12). Everything a journey crosses besides its seam is already proved lower down, which is why there are twelve and not four hundred.

What only an end-to-end test proves

The glossary defines end-to-end testing as “a test type in which business processes are tested from start to finish under production-like circumstances”. Two phrases in it carry the weight. “From start to finish” means the journey ends at the outcome a customer needs — the parcel in the warehouse, the money back on the card — not at the last screen. “Production-like” means the configuration, the routing and the topology of the real thing. Notice too that ISTQB calls it a test type, not a level. The test pyramid draws it as the top layer, but what defines it is what it covers, not which part of the code it sits in.

Every test below it works in a controlled setting. A unit test replaces its neighbours with fakes. An integration test uses a real database and a stand-in for the payment provider. A contract test proves two services agree about a message without either running the other. All of that is valuable, and none of it can show that the deployed system, with its real routing, real environment variables, real session handling and real front-end build, lets a person finish what they came to do. The classic defect that escapes a well-tested system is not a wrong calculation. It is a misconfigured redirect, a attribute that breaks the session in one browser, a on in and off in production. Each lives at a seam, and every lower test replaced exactly that seam.

Split a journey into segments and test each one with a stand-in where the next part would be, and every segment can pass while the journey fails. The defect here is not in any part: the real queue between orders and the warehouse refuses a message over 256 KB, and the stand-in used in segment 3 accepted anything, so a large order passes every segment test and never reaches the warehouse. A stand-in can only behave the way its author believed the real thing behaves, which is exactly what is in doubt at a seam. That is what an end-to-end test buys and nothing below it can: the joints, run for real. Each case at the end of the page failed at a joint like this one — a test that stopped just before it, or ran against a stand-in, or in a place shaped differently from production.

The diagram is the mechanism behind every case at the end of this page. Split a journey into segments, test each segment with a stand-in at its joint, and every segment can be green while the journey fails — because the defect lives in the joint, and the joint is the one thing no segment test ran. Martin Fowler adds a warning about the words: teams “conflate the concepts of end-to-end tests, tests, and customer facing tests. These are all orthogonal characteristics.” A test that clicks through a browser against a mocked back end is a UI test. It is not end to end, and it cannot prove a seam it has replaced.

Pyramid, trophy, honeycomb — three shapes, one argument about cost

Mike Cohn described the test pyramid in his 2009 book Succeeding with Agile, and Martin Fowler’s 2012 note made it famous: many unit tests at the bottom, fewer service tests in the middle, few end-to-end tests at the top, because tests that run end to end through the interface are “brittle, expensive to write, and time consuming to run”. ISTQB’s glossary now has an entry for it. Since then other shapes have been drawn, each by people working on a different kind of system, and the table puts them side by side.

ShapeFromWhere the bulk isEnd to endFits when
PyramidMike Cohn, 2009; Martin Fowler, 2012Unit testsFew, at the topMost of the logic lives inside one codebase
70 / 20 / 10Google Testing Blog, 201570% unit, 20% integration10%, “as a good first guess”A team that needs a number to start from
TrophyKent C. Dodds, 2018Integration — “Mostly integration”, with static checks as the baseA fewA front end, where the meaningful unit is a component with its children
HoneycombSpotify, 2018Integration tests through each service’s own API“even fewer … (ideally none)”Microservices, where the complexity lives in the interactions
Ice-cream coneThe anti-pattern both Fowler and Google nameEnd-to-end and manual testsMost of the suiteNever on purpose

The shapes disagree about the middle and agree about the top. Spotify’s honeycomb wants “even fewer Integrated Tests (ideally none)”, where an integrated test is one “that will pass or fail based on the correctness of another system”. Google’s 2015 post settles for about a tenth. Dodds keeps a few. The disagreement is real and worth leaving visible: a team of independent services can test most interactions through contracts and each service’s , while a shop that takes money across five systems in one customer’s minute cannot. What none of them says is that the top layer should be large. Fowler states the reason it is small as an assumption rather than a law: “If my high level tests are fast, reliable, and cheap to modify - then lower-level tests aren’t needed.” They rarely are.

The pyramid is usually drawn as advice about proportions, and by count the shop’s tests are a textbook one: 2,140 unit cases, 406 API, contract and integration cases, and twelve journeys. Count the same tests by the minutes they take and the shape turns over. The unit cases finish in 70 seconds, the middle layer in about nine minutes and the twelve journeys in about thirteen — so half a percent of the cases cost more time than everything else together, before counting the time spent when one of them fails for a reason that has nothing to do with the change. That is the whole argument for keeping the top small: not that end-to-end tests are bad, but that each one is the most expensive test a team owns, so it has to prove something nothing cheaper can.

What a red journey costs — the arithmetic of flakiness

The runtime is the obvious cost and the least important one. The real expense is the distance between a failure and its cause. When a unit test fails you are looking at one function. When journey 9 fails you are looking at a browser, a front end, a warehouse , a refund service, a payment sandbox, an email provider and an environment — and possibly at none of them, because the test may simply have checked the inbox before the email arrived.

Size makes that likelier. Google found that over a week 0.5% of its small tests were , 1.6% of its medium tests and 14% of its large ones. A journey is the largest test a team owns. And small rates compound: if each case fails for no reason with probability p, a run of n cases goes red with nothing wrong with probability 1 − (1 − p)ⁿ. The table works it out.

Journeys in the suiteEach flakes 0.5% of runs2% of runs5% of runs
125.8%21.5%46.0%
6026.0%70.2%95.4%
40086.5%≈ 100%≈ 100%
Small failure rates compound. If each journey fails for no reason on a fraction p of runs, a run of n journeys goes red with nothing wrong with probability 1 − (1 − p)^n, and the curve climbs faster than intuition expects. At 2% a journey, sixty journeys are red on seven runs in ten; at the best rate in the table, four hundred are red almost nine times in ten. A suite that is red most of the time is a suite people stop reading, which is why adding journeys stops adding protection long before it stops adding cost. The shop keeps twelve: at 0.5% each they go red for no reason about once in seventeen runs, rare enough that every red run can be investigated rather than re-run.

Read the table as a budget, not a complaint. A suite of sixty journeys at 2% each is red on seven runs out of ten when nothing is wrong. Four hundred journeys at the best rate in the table are red almost nine times in ten. That is why “we will just add retries” is the wrong first move, and why ten times the journeys is not ten times the protection — it is a suite that will be ignored. Twelve journeys at 0.5% go red for no reason about once in seventeen runs, which a team can afford to investigate every time.

Why a journey went redWhat it actually meansWhat removes it
The system is genuinely brokenThe reason the journey exists.Nothing should — everything below is the tax on keeping this signal.
The test checked before the system finishedA timing bug in the test — the largest single cause of flakiness in Luo et al.’s study (Regression testing).Wait for the condition: the email in the inbox, the order in the warehouse.
The data was not what the test assumedShared state between journeys or people.Each journey creates its own customer, order and card, and removes them.
An element moved in a redesignUpkeep, not a defect.Find elements by role and name or by a test-id, never by CSS class or position.
A third party was slow or downA decision postponed: which dependencies belong inside the test.Decide it in writing, per dependency — the table in the next-but-one section.

Choose journeys, not features

The selection mistake almost every team makes is one end-to-end test per feature. Features are how the backlog is organised. They are not how a customer moves through the product, and covering them one by one gives hundreds of slow cases that mostly re-prove logic already proved below. Choose journeys instead: a small number of paths a customer actually completes, each crossing several services, because the crossing is what is being tested.

  • The money path — journeys 1, 4–6

    Find, add, pay, and the order arrives. If exactly one end-to-end test exists, it is journey 1, because it crosses every service the business depends on.

  • Getting in and staying in — journeys 2, 3, 11

    Sign up, sign in, stay signed in after a reload, recover a password. Session and cookie behaviour is invisible to every lower test.

  • Across a boundary — journeys 7–10

    Work one service starts and another finishes, often hours later in real life: a return the warehouse confirms, a refund an email reports.

  • A hard rule — journey 12

    A permission boundary, a regulated disclosure, an age check. Places where being wrong is a legal event rather than a support ticket.

A sizing heuristic, the one in the callout at the top: one journey for each thing the business could not survive losing, plus one for each seam that exists only in the deployed system. For most products that lands between ten and forty. If yours is in the hundreds, the suite is not more thorough than everyone else’s; it is carrying work that belongs two levels down and paying the highest price per case in the codebase to do it. And when a journey finds a bug, follow Fowler’s rule from the Regression testing page: reproduce it at the lowest level that can, so the journey is the second line of defence, not the only one.

Making twelve journeys trustworthy

A trustworthy end-to-end suite does not come from better assertions. It comes from removing every source of variation that is not the behaviour under test, and five of them are worth handling on purpose.

  • Wait for a condition, never for a duration. A fixed sleep is too short on a loaded machine and wasted on a fast one; waiting for the element, the email or the warehouse record is both faster and stable.
  • Give every journey its own data. It creates the customer, the order and the gift card it needs, and removes them afterwards. A journey that depends on a record someone else made fails on a Tuesday for no reason.
  • Find elements the way a person does — by role and visible name — or by a , never by a CSS class or a position, both of which change whenever a designer touches the page.
  • Control the clock. A journey that depends on today’s date passes in March and fails on the last day of a month; set the date, and then walk the dates that break things on purpose — the 30th day of a return, the 29th of February.
  • Capture enough on failure to diagnose without reproducing: a trace, a video, the network log and the browser console. The cost of a red journey is the investigation, and artefacts are what shorten it.

The sixth source is the outside world, and it needs a decision per dependency rather than a default. The test asks one question about each: is this part of the journey I am proving, or something the journey merely touches?

DependencyIn the shop’s journeysWhy
Payment providerReal, in its sandboxThe money path is the point of journeys 1 and 4–6; the sandbox has cards for success, decline and 3-D Secure.
Email providerReal, in test mode, into a test inboxJourneys 2, 3, 8 and 9 end with an email a customer acts on.
Carrier’s label serviceStub, checked by a contract testThe carrier has no sandbox; the journey proves the shop’s side of the return.
The assistant’s modelReplayed from a recordingJourney 7 proves the plumbing; the nightly evaluation judges the answers.
Analytics, maps, chat for marketingBlocked at the network boundaryNot part of any journey’s outcome, and the commonest source of slow, random reds.

Retries deserve a policy rather than a default. Retrying a whole journey hides real intermittent bugs, because a race in the product looks exactly like a flaky test from the outside, and the retry turns a genuine defect into a green tick. The shop’s rule is the one on the Regression testing page: one retry at most, recorded as a signal in its own right, and a journey that needed two retries in a week goes to quarantine. A suite whose green result depends on retries is not green; it is unmeasured.

Three failures where a test stopped one step short

In none of these was the testing skipped. Each time a test ran and passed. It checked a step short of the outcome that mattered, stopped just before the seam where the defect lived, or ran in a place that was not shaped like production.

FailureWhat was tested, and what happenedThe step the test stopped short of
Windows Azure, 29 February 2012The leap-day bug itself is told on Data Modeling. Repairing seven half-updated clusters that night, engineers tested the fix on one server: its virtual machines “started successfully and appeared to be healthy”. The package also carried a networking plugin built for the newer agent. It was pushed to every server in those clusters at once, and their virtual machines lost the network.The outcome a customer needs: can I reach my machine? Microsoft wrote that the test “had not included testing network connectivity to the VMs”; the second attempt, at 3:40 a.m., was tested “this time verifying VM connectivity”.
TSB, 22 April 2018The migration weekend is told on Release Planning. Production ran in two data centres side by side. On 28 February a testing forum chose to performance-test both together; the bank then accepted a proposal to test one, to keep live services such as cash machines running. After go-live, a customer signed in through one data centre and the next request went to the other, where the session did not exist: “your session has expired”.The production topology. The FCA’s notice: services “may functionally work end-to-end with one user” and not under load, and had the test run in both data centres, “it is likely that this issue would have been identified”.
Boeing Starliner, 20 December 2019The uncrewed test flight missed its orbit insertion burn: the capsule’s mission clock was wrong, so the software believed the burn had happened hours earlier, and the flight never reached the space station. Boeing had tested the software in chunks. The joint simulation with the rocket’s maker stopped at separation; the burn came about half an hour after liftoff. A second error, a wrong thruster map for the service module, passed its qualification test on an emulator that did not have the correct map either.The next seam. Boeing’s programme manager: “If we had run that integrated test for a number of minutes longer, it would have uncovered the issue.” A stand-in at a seam proves only what the stand-in was built to believe.

Where it degrades

The honest limit is that twelve journeys prove twelve paths worked once, in one environment, with one set of data. Production-like is not production: the real traffic, the real third parties and the real calendar arrive only after the deploy. That is where the smoke gate and synthetic monitoring take over, running the same journeys against production on a schedule. And an end-to-end suite cannot find a defect on a path nobody walked; it can only keep the walked paths from breaking unnoticed.

  • An ice-cream cone: most of the testing done through the browser, few tests below, so every failure is an hour of investigation.
  • One test per feature, so four hundred cases mostly re-prove logic already proved in milliseconds.
  • A browser test against a mocked back end, reported as end to end.
  • Journeys that end on the confirmation screen instead of at the outcome — the parcel, the refund, the email.
  • One long case walking fifteen screens, so a failure says only that something in fifteen screens is broken.
  • Journeys that depend on running in order, so one failure cascades into six and the report describes nothing.
  • A suite run only at night, so a regression is blamed on a day of merges rather than on one commit.
  • An environment kept by hand that nobody can rebuild, which fails for its own reasons more often than for the code’s.
  • Retries on everything, and sleeps scattered through the code as the standard fix.

When to use it

Use it when

  • For the handful of journeys the business could not survive losing, each crossing several services in the deployed system.
  • For behaviour that exists only once the real pieces are joined — sessions, redirects, configuration, the built front end.
  • Against an environment rebuilt from the artefact that ships, with production’s topology, so a pass says something about production.
  • Spread over parallel workers, so the suite is fast enough for every merge rather than once a night.

Avoid it when

  • For validation rules, error copy, sorting and arithmetic — anything a component or API test proves in milliseconds.
  • As the main body of the test suite, where the cost per case is highest and the cause furthest from the failure.
  • Against a shared, long-lived environment with hand-made data, where every result depends on what a colleague did an hour ago.
  • With blanket retries to keep the pipeline green, which turns genuine intermittent defects into passing runs.

Sources and method

What this page stands on

  • 12 sources
  • 3 documented failures
  • Checked October 18, 2026

Researched with Claude. Finding and cross-checking the primary sources was done with Claude (Anthropic). Selection, writing and fact-checking: the Anatomy of IT Product editors.

Found this useful?

Share it with someone who is working on the same problem.