Skip to content

Lesson 2 of 9 · 16m

The Testing Pyramid, Done Pragmatically

Unit tests for logic, integration tests for seams, end-to-end tests for the golden path — and why the shape matters.

The pyramid says: many fast unit tests at the bottom, a narrower band of integration tests in the middle, and a few slow end-to-end tests at the top. Teams get the shape wrong more than the counts — they write E2E tests for everything and wonder why CI takes an hour and every failure is flaky.

Unit tests: the fast feedback loop

Test one function or class in isolation, in-process, no I/O. They run in milliseconds, they pinpoint exactly which line broke, and they are cheap enough to write in bulk. Pure logic — validation, parsing, calculation, state machines — should live here.

Integration tests: the seams

Test the boundary where your code meets the database, the HTTP client, the filesystem. These are slower — real Postgres or a real HTTP round-trip — and they catch the bugs unit tests cannot: wrong query shapes, serialization edge cases, transaction ordering. You need fewer of them, but the ones you need are load-bearing.

End-to-end: the golden path only

A browser-level test that exercises the real stack for the one path that matters most: "a member signs in and posts a thread." E2E is the most expensive to run and the flakiest to maintain — every layer above the unit has more ways to fail for the wrong reason. Spend it on the paths where "if this breaks, the product is broken."

Try it yourself — where a bug lives, in JS

// A unit-level bug: this function alone is wrong — nothing else involved:
function normalizeTag(s) { return s.trim().toLowerCase(); }
console.log(normalizeTag("  Python  ")); // "python"

// An integration bug: wrong query shape / wrong endpoint — only shows at the seam.
// An E2E bug: only shows when the whole stack runs together.
console.log("Each level catches what the level below cannot.");

The number that matters

Not coverage percentage — the ratio: roughly 70% unit, 25% integration, 5% E2E of your suite, tuned to your codebase. Invert it and CI becomes the bottleneck instead of the safety net.