Diagram · Testing

What to Test at Which Level

The test levels drawn with what each is good at, what it costs, and the rule that decides where a test belongs — plus the activities that no level covers.

SVG. No sign-up, no email.

The familiar pyramid says there should be many small tests and few large ones. It is correct and it does not tell you where any particular test belongs, which is the decision people actually face.

The rule that does: test a behaviour at the lowest level that can genuinely test it. The diagram below is that rule, with what each level costs.

Test levels — what each is for, and what it costs Levels: Unit (logic, in,milliseconds), Integration (boundaries between,parts), Contract (agreement with a,service), End-to-end (real journeys, few), Manual (judgement,,exploration). Cost per test: Milliseconds (run on every save), Seconds (run on every,change), Seconds (run on both sides), Minutes (and the flakiness,lives here), Human time (the scarcest input). No level covers these: Exploratory (finds the unimagined), Usability (someone who did not build,it), Accessibility (with real assistive tech), Load and failure (at and past the limit). Levels Unit logic, in milliseconds Integration boundaries between parts Contract agreement with a service End-to-end real journeys, few Manual judgement, exploration Cost per test Milliseconds run on every save Seconds run on every change Seconds run on both sides Minutes and the flakiness lives here Human time the scarcest input No level covers these Exploratory finds the unimagined Usability someone who did not build it Accessibility with real assistive tech Load and failure at and past the limit Best value, usually undersized Expensive — keep it small and deliberate
A test belongs at the lowest level that can genuinely exercise the behaviour. The bottom lane is what no level covers.

Applying the rule#

"The lowest level that can genuinely test it" does the work, and the word doing most of it is genuinely. A behaviour can be simulated at a low level with enough mocking, and at some point the test is asserting that the mocks were configured as the test configured them.

Two questions settle nearly every case:

Does this test need a running system to be meaningful? If not, it is a unit test. Pricing rules, validation, state transitions, calculations — these need no database and no browser, and putting them behind one makes them slower and less able to cover their own edge cases.

Is the thing being tested the interaction between two parts? Then it is integration, and mocking one of the two removes the thing being tested. This is the level most suites are short of, and it is the level that catches the most defects per test in nearly every codebase that measures it.

Why end-to-end is marked expensive#

Not because it is slow, although it is. Because of a second-order effect.

End-to-end tests are the ones that fail intermittently — real browsers, real timing, real networks, real ordering. A suite with intermittent failures teaches people to re-run rather than investigate, and once that reflex forms, the suite has stopped being able to fail usefully. A legitimate failure looks identical to the noise.

Keep them, keep them few, and keep them for journeys that genuinely span everything: sign-up, checkout, refund, export. Anything that could have been tested one level down should be.

Contract testing, the level people skip#

Between integration and end-to-end sits a level that removes most of the reason for the latter.

A contract test asserts the agreement between a consumer and a provider: given this request, this shape of response. Both sides run it. The consumer can then test against a stub with confidence, because something separately guarantees the stub matches reality.

This is what turns "we need an end-to-end test to be sure the integration works" into "we have a contract test on both sides", and it is the single most effective way to shrink an end-to-end suite without losing coverage.

The bottom lane#

Drawn as a set because none of these is a level, and none is optional.

Exploratory testing finds what nobody thought of. Automated tests check what somebody imagined in advance; that is their nature, not a shortcoming. A team that has automated everything has thoroughly tested its own imagination.

Usability needs someone who did not build it. The person who built a screen cannot see it for the first time again.

Accessibility needs the real assistive technology. Automated checkers find missing attributes. They cannot tell you that the flow is unusable with a screen reader, and that is the finding that matters.

Load and failure behaviour are properties of the system that no functional test at any level exercises.

Using this diagram#

Count your tests per level, and count minutes per level. The common shape is a large unit layer, a thin integration layer, and an end-to-end layer holding most of the runtime and most of the flakiness.

The fix is almost never "write more tests". It is moving assertions down a level, adding contract tests at the boundaries, and deleting the end-to-end tests that duplicate them.

Back to Testing