Chapter Twelve · Testing the Service

Testing the Service

Stagedoor's suite was 400 tests that mocked the database, passed in 8 seconds, and was green on the morning after all three wounds. Five topics rebuild it in layers: the shape and what each layer catches, a real PostgreSQL 18 in a container with one rolled-back transaction per test, a fake Payrail that behaves and a contract test that keeps it honest, failure tests that stop the database on purpose, and a load test of the on-sale mix that finds the pool limit at 800 requests a second, six weeks before the buyers would have.

5 topics

The oversell, the double charge and the late emails all lived in the boundary between Stagedoor's code and the systems around it: Postgres under two concurrent transactions, a Payrail call that lost its answer, a render that ran inside the request. The suite of 400 tests had replaced exactly those systems with mocks that returned what the author expected, so it tested the author's beliefs and never the boundaries, and it could not have been red on the night. This chapter is the suite Marek built instead, and its rule is one sentence: a boundary is tested against the real thing on the other side of it, or against a fake that behaves like it, never against a mock that asserts.

The layers follow from the rule. Domain tests, 1,050 of them in 4 seconds, run the rules against the in-memory repository, the frozen clock and the fake stream of Chapter 4, and touch nothing outside the process. Storage tests, 350 in under a minute, run the real SQL against a postgres:18 container started once per session, migrated from empty, with each test inside a transaction that is rolled back, and 9 marked tests that use two real connections because a race cannot be seen from one. The Payrail client is replaced by a 40-line fake that charges, declines the test card and remembers by key, and the client's own retry and breaker are tested against a scripted transport; a nightly contract test against the sandbox is what keeps the fake true. Failure tests inject every row of the dependency table of Chapter 7, the container paused, the fake timing out, the config pointed at a closed port, and assert the degrade and the recovery. The load test sends the on-sale mix at 3,000 requests a second against a staging sized like production and watches which gauge moves first.

No new wound opens here. The chapter closes the old three a second time, as regression tests that would fail if any fix were removed, and it finds the three limits that Chapters 6 and 9 built mechanisms for without ever knowing their number: the pool at 800, the stampede at 2,000, the CPU at 4,500. Chapter 13 is what the service reports about itself once it is running, and Chapter 14 is what the load test's numbers turn into on the night.

Three wounds, and the test that now fails if each fix is removed
Seat 14C sold twicetest_concurrent_holds_on_one_seat
Two connections, one seat, two holds at once against a real PostgreSQL 18. Exactly one 201, one row in holds. Topic 64.
One buyer charged twicetest_retried_checkout_charges_once
A timeout on the first attempt, a retry, and the same Idempotency-Key on both requests to a scripted transport. Topic 65.
Emails 40 minutes latetest_order_confirms_before_pdf_is_rendered
The order confirms in under 200 ms with the render still queued; the queue age line watched through the load test's plateau. Topics 63 and 67.

Topics in This Chapter