Skip to main content

A Practical Testing Pyramid for REST APIs

1 min read

The pyramid we actually use

LayerCountSpeedWhat it catches
Unit300+2sLogic errors, edge cases
Integration5015sDB queries, middleware wiring
Contract205sAPI response shape changes
E2E53mDeployment sanity (smoke only)

The insight

We removed all but 5 E2E tests. The remaining ones just check that the server starts, serves a 200 on /health, and can complete a full write→read cycle. Everything else is covered by faster layers.

Contract testing with golden files

func TestAPIResponseShape(t *testing.T) {
    resp := testServer.Get(t, "/api/users/1")
    golden.Assert(t, resp.Body, "testdata/get-user.golden.json")
}

When the API changes, update the golden file. When a PR forgets, the test fails.

What I learned

The traditional testing pyramid recommends many unit tests, fewer integration, fewer E2E. What it doesn’t say: E2E tests should be smoke tests, not comprehensive coverage. Comprehensive E2E is a maintenance sink.