BOOKS DEEP-READ · CONTINUOUS DELIVERY · CH 4
Continuous Delivery · Ch 4 · Jez Humble & David Farley · 2010
Before any app update ships, somebody has to confirm it isn't broken. The catch: there are thousands of things to confirm — who confirms them, and when? Chapter 4 of Continuous Delivery doesn't answer "test more." It answers: split "testing" into several completely different jobs, and give each one to different people at different moments.
Putting up a building involves three kinds of checking. First: the bricklayer runs a spirit level over each stretch of wall — takes seconds, and tells you exactly which brick is off. Second: once a floor is capped, someone walks it and checks the water and the wiring — slower, but it catches what no single brick could reveal. Third: when the building is done you bring in a veteran inspector for two days, and he opens the cupboard you never thought to open and says "you can't turn around in this doorway carrying luggage."
All three are necessary, and their economics are wildly different. The scary part is that many teams only have the third one — nobody levelled a wall for eighteen storeys, and when the inspector says "it started leaning at floor three," you're in demolition territory.
The old default: programmers finish, throw it over the wall to a separate test team, and in the last few days everyone works through a checklist of a few hundred items by hand. Three things follow inevitably. One, feedback is far too late — the problem was planted three weeks ago, and whoever wrote it has long forgotten what they were thinking. Two, the cost only climbs — more features means a longer checklist, while releases are supposed to get faster. Three, the work can't be banked — you'll click through it all again next round, and nobody can say which items got skipped.
The chapter re-sorts testing by two questions: is this check trying to help the team not get it wrong, or trying to find out what's wrong with the thing already built? And does it care about business correctness, or technical soundness? Two by two, that's four kinds of work.
Once you sort them, the crucial dividing line appears by itself: checks that are identical every time and answer yes-or-no go to machines, which run them thousands of times a day; checks that need curiosity and experience to "find the problem nobody thought of" stay with people. Getting those two backwards is what's actually wrong with most teams: the machines idle while humans click through the checklist again.
The machine's half needs layering of its own: do lots of the small fast checks (thousands, done in minutes, and a red one tells you which brick), keep the slow whole-system checks few and precious (dozens, covering "can a user actually get their money out") — because whole-system checks are slow, expensive, and every so often fail for no reason at all; pile up enough of them and nobody believes any of them.
The human half is the mirror image: hand off all the clicking-through-a-checklist, and spend the reclaimed time wandering the product like a real user to see what falls out — a machine only ever checks the handful of things you wrote down in advance.
One honest cost: automated tests are code too — they must be written and fed. Written badly, they cry wolf daily, slow everyone down, and end up ignored by the whole team.
Testing isn't the last step before release; it's a bundle of different jobs running from day one. Give the repeatable ones to machines and do many small ones rather than a few big ones; leave the imaginative ones to people — you need both, and neither can stand in for the other.
Want the quadrants, the ratios, the comparison tables and the pipeline diagram? → Switch to the deep read
You think a "testing strategy" is about how much to test, who tests it, and what coverage number to hit. The chapter is actually asking something else: which class of risk gets answered by whom, when, and at what cost? The answer has two halves. First, a taxonomy — two axes, business-facing vs technology-facing and supporting the development process vs critiquing the finished product, cut testing into four quadrants, each with a different question and a different automation fate: anything repeatable with a binary answer goes to machines that run it daily; anything that relies on human curiosity to surface "the problem nobody thought of" (exploratory, usability) stays with people. Second, a starting order — new project, mid-project, legacy system each need a different first move. The whole chapter rests on one stance: testing is not a phase, it's an activity that runs throughout; quality belongs to the whole team, not to a test department.
The closing chapter of Part I, and the settling of a debt from Chapter 3: continuous integration demands "a comprehensive suite of automated tests," and this chapter says what that suite should actually look like, who writes it and where it runs. Downstream, Chapter 5's deployment pipeline arranges these four kinds into gates (Chapter 7 runs unit tests in the commit stage, Chapter 8 unfolds automated acceptance testing, Chapter 9 handles non-functional testing). Today's counterparts: the test-pyramid argument, Google's small / medium / large test sizes, contract testing, and the "canary plus observability" habit of shifting some verification right into production.
Start with a scenario. A 30-person team runs a payment gateway on a two-week release train, with testing squeezed into the last three days: 6 testers work a 400-item manual regression checklist end to end, two days a pass, and "just do the important ones" when time is short. Three structural leaks:
What happens if you don't fix it? A "testing phase" black hole of unpredictable duration grows at the end of the project — the same disease as Chapter 3's "integration phase" black hole: something that should be done daily, settled in one lump at the end. But the chapter equally rejects the other extreme: going all-in on automation doesn't work either, because a machine only verifies the assertions you wrote in advance, and the truly expensive defects are usually the ones nobody thought to assert. So the fix is not "automate everything" — it's classify first, then decide each class's fate.
The book opens on this: testing is a cross-functional activity running the length of the project, with quality owned by the whole team rather than handed to a downstream department. In practice that's three moves: testers help write acceptance criteria from day one, pinning down "what done means" with analysts and developers before coding starts; the definition of done includes "tests pass"; and when a defect escapes to late stages or production, write an automated test that reproduces it before fixing it — otherwise the same hole gets stepped in twice.
The deeper reason is what the safety net buys you: the nerve to change things. Without it, refactoring is gambling, and a team will naturally choose to route around code and copy-paste instead. This is the reciprocal of Chapter 3: CI makes you integrate daily, the test net makes you dare to.
The chapter's skeleton is the testing quadrants, proposed by Brian Marick and popularised by Crispin and Gregory in Agile Testing. Each axis asks one question. Is this test business-facing (written in domain language, a customer can read it) or technology-facing (only developers can)? Does it support the development process (written before or during the work, to keep defects out) or critique the finished product (run afterwards, to find what you didn't think of)?
The technology-facing box is the developer's safety net: unit tests (thousands finish in minutes, and a red one points almost to the function), component / integration tests (a module plus its real dependencies — an order of magnitude slower, but they catch the wiring problems unit tests can't see), and deployment tests, i.e. smoke tests — a handful of checks run right after every deployment asking only "is the service alive, is the config wired to the right thing?" Cheapest to build, highest return, most often forgotten.
The business-facing box is automated functional acceptance testing: written in business language ("given a zero balance, when the user places an order, then it is rejected with a top-up prompt") and written before development as the acceptance criteria, run in an environment as close to production as you can get. It holds two jobs at once — the verdict on "is it done" and, from then on, a permanent regression net. The book is clear-eyed about the price: this is the most expensive, most brittle and hardest-to-maintain of the four, because it needs test data, a whole environment, and it crosses the interface. So keep the count modest (dozens, not thousands), cover only the most valuable business paths, and write it in layers — business intent in one layer, the technical driver in another — so a UI change doesn't turn everything red.
The manual box holds three things whose value comes from a human. Showcases: demo the real system to the customer at the end of an iteration; this exposes "did we build the right thing" — misread a requirement and every automated test is still green. Usability testing: only a person can say "I can't get through this flow." Exploratory testing: not random clicking but a deliberate creative activity — learning the system while designing new experiments, aimed squarely at the corners nobody wrote assertions for. From which the book states automation's real purpose: not to replace testers, but to buy them out of repetitive manual regression so they can do these three things.
The non-functional box is capacity, performance, security, robustness. It only works if the requirement is first quantified into a decidable threshold (say, "p95 response time under 200 ms at a peak of 3000 QPS" — p95 meaning: line up a hundred requests by duration and take the 95th fastest); otherwise pass or fail can't be judged automatically and it degrades into a report nobody reads. It also needs specialised tooling and a near-production-scale environment, which is why it sits after acceptance testing in the pipeline.
To keep those tests fast and stable you can't call the real payment provider or send real text messages every run — external dependencies are slow, unstable, have side effects and may cost money. Test doubles are the stand-ins, and the book uses Gerard Meszaros' taxonomy: dummy (pure placeholder), fake (a working simplified implementation, like an in-memory database), stub (canned answers to expected calls), mock (a stub that also asserts how it was called).
State the cost plainly: the more mocks, the more your tests are welded to implementation detail — you end up asserting how the code does it rather than whether the thing got done, so one legitimate refactor turns a hundred tests red and the team quickly learns to stop refactoring. The book's balance point: use doubles to isolate, but keep a small set of tests that really hit the external system and run them periodically, or all you've proven is that your assumptions and your fakes agree. One terminology trap: "integration testing" in this book means testing against external systems, not today's common sense of "tests that span modules."
The book refuses a one-size-fits-all checklist and gives strategy by project state instead (see Table 3 below). The path worth memorising is the legacy one: Feathers' definition is "code without tests is legacy code," so the order is — automate the build and deployment first (Chapter 2), then write characterization tests around the small piece you are about to change (record its current behaviour as-is, right or wrong), and only then change it. Global coverage is a trap here: coverage is a diagnostic signal, not a target — a suite at 100% coverage with almost no assertions is entirely possible.
The quadrants finally land on a timeline: earlier gates are faster and cheaper and should catch most defects; later gates are more production-like, broader and slower.
Table 1 · The quadrants at a glance: role, automation fate, and what breaks if you skip it
| Quadrant | Typical tests | Automate? | Pipeline gate | If you skip it |
|---|---|---|---|---|
| Tech · supporting | unit, component, deployment / smoke | Must automate | commit stage (≤10 min) | nobody dares refactor; each change is a prayer |
| Business · supporting | functional acceptance tests | Must automate | acceptance stage | you build the wrong thing, with no regression net |
| Business · critiquing | exploratory, usability, showcase | Cannot automate | manual stage, on demand | you only ever find problems you already imagined |
| Tech · critiquing | capacity, performance, security | Automated, humans interpret | non-functional stage | every feature correct, and it folds under load |
Table 2 · The economics of the three automated layers — why the shape has to be a pyramid
| Unit | Component / integration | End-to-end acceptance | |
|---|---|---|---|
| Time each | milliseconds | seconds | tens of seconds to minutes |
| A failure points to | a function | a module boundary | "this flow is broken", nothing more |
| Flakiness risk | very low | medium (env and data) | high: network, timing, dirty data |
| Maintenance | low, but couples to internals | medium | highest: env, test data, UI churn |
| What it proves | this code works as designed | the modules are wired right | business value can actually be delivered |
| How many | thousands (the bulk) | hundreds | dozens, main paths only |
Why can't it be inverted? Simple arithmetic: with 200 end-to-end tests each failing randomly 0.5% of the time, the chance of a fully green run is only 0.995²⁰⁰ ≈ 37% — two runs in three go red, mostly not for real bugs. Once red is normal, Chapter 3's "stop the line when it goes red" discipline is void on the spot. That's the lethal part of the ice-cream-cone anti-pattern: not that it's slower, but that it costs the whole suite its credibility.
Table 3 · Three starting points: what to do first, what not to do
| Starting point | Do first | Don't | Why |
|---|---|---|---|
| New project | TDD and acceptance criteria from day one | don't say "ship now, tests later" | marginal cost is lowest now and only rises |
| Mid-project | automate acceptance tests for the busiest main paths, even just 10 of them | don't halt development to "fix coverage" | block the catastrophes first, then test what you touch |
| Legacy system | automate build and deployment → write characterization tests around the part you're changing | don't chase global coverage or big-bang rewrites | the net follows the change: test where you cut |
Table 4 · Handling dependencies: four doubles and the real thing
| Approach | What it does | Cost / risk | When |
|---|---|---|---|
| Real dependency | calls the real database / third party | slow, unstable, side effects, may cost money | keep a small set on a schedule to check assumptions still hold |
| Fake | working simplified implementation (in-memory DB) | may differ subtly from the real behaviour | default for component tests |
| Stub | canned answers to expected calls | fixes inputs and outputs only; stable | the default choice for most cases |
| Mock | also asserts how it was called | welds tests to internals; refactor turns all red | only when the interaction is the requirement ("charge exactly once") |
This chapter is the loading list for the deployment pipeline: Chapter 5 supplies the gates, this chapter decides what goes in each. In an interview, "what's your testing strategy" is not answered well by a coverage number — it's answered with the items here: the ratio and runtime of each layer, who writes acceptance tests and when, how flaky tests are handled, how a legacy module gets started.
70% unit / 20% integration / 10% end-to-end — the same layering the chapter argues for, with the numbers nailed down.M. Wacker, "Just Say No to More End-to-End Tests", Google Testing Blog 2015 ↗80% / 15% / 5% and a standing rule to "always write the smallest possible test."Winters, Manshreck & Wright, Software Engineering at Google, Ch.11 Testing Overview ↗60% is treated as acceptable, 75% commendable and 90% exemplary, while the post stresses that coverage is not a proxy for test quality and shouldn't become a box to tick.Google Testing Blog, "Code Coverage Best Practices", 2020 ↗① In one line: testing is not a phase but a cross-functional activity running throughout; quality belongs to the whole team, not a downstream test group.
② The skeleton is the four quadrants: business-facing / technology-facing × supporting development / critiquing the product — each with its own question, writing moment and automation fate.
③ The dividing line: repeatable, binary-answer checks go to machines; the ones needing human curiosity stay with people — you need both, and neither substitutes for the other.
④ Automated acceptance tests are written in business language before the code, serving as both criteria and regression net; but they're the most expensive and brittle, so keep them few, valuable and layered.
⑤ The shape must be a pyramid: most unit, fewest end-to-end. 200 E2E tests at 0.5% flakiness each leave roughly a 37% chance of an all-green run — invert the shape and red stops meaning anything.
⑥ Doubles buy speed and isolation, but more mocks means more coupling to internals; keep a few tests that really hit external systems. Note the book's "integration test" = against external systems.
⑦ The starting point sets the order: new projects do it right on day one; mid-project, write ten acceptance tests for the main paths first; legacy, automate deployment then write characterization tests around what you're changing — never chase global coverage.
⑧ Evidence: Google suggests 70/20/10, SWE at Google gives 80/15/5, Google states plainly that coverage is no proxy for quality, DORA requires tests maintained primarily by developers, and Spotify's honeycomb shows the ratios follow your architecture.