Fixture Diet
Cuts test setup down to the few facts the test actually depends on, so the test says what it means.
When to reach for it
When a test file opens with thirty lines of setup, or when adding one field to a model breaks a dozen tests that were never about that field.
What changes
- Each test shows the values its assertion depends on, in the test body, named for the role they play — everything else moves behind a builder with defaults.
- You can read a test top to bottom and point at the input that causes the outcome without opening a shared fixture file.
- Adding a required field to a model touches one builder instead of every test that happens to construct that model.
- Shared mutable fixtures are replaced by per-test construction, removing a whole class of order-dependent failures.
- Setup lines drop by a number you can count, and a deliberate break in the behaviour still turns the slimmed tests red.
Pairs with
- Behaviour, Not CoverageTurns “add some tests” into tests that state what the code promises, instead of tests that exist to move a percentage.
- Failing Test FirstMakes the agent prove the bug exists — with a test that fails for the right reason — before it is allowed to fix anything.
- Flake HuntFinds out why a test is intermittent, instead of retrying it until the pipeline turns green.
Fixture Diet
Setup is not free. Every line of it is something the reader has to hold in their head while deciding whether the test proves anything at all.
1. Find what is load-bearing
Take one test. Delete setup lines until it fails, and look at what the failure demanded. That is the real input. Everything you removed without consequence was decoration.
2. Rebuild the test around the values it asserts on
Values the assertion depends on belong in the test body, visible, named for their role in the story:
const expiredAt = daysAgo(1)in the testconst cart = buildCart({ items: [] })in the test- Everything else behind a default nobody has to read
3. Move the remainder behind a builder
One function per entity that returns a valid object and accepts overrides. Tests then read as "a subscriber, except their trial ended yesterday", which is the sentence you would have said out loud anyway.
4. Stop sharing mutable state
Build fresh objects inside each test. A shared fixture that any test can mutate is an ordering dependency waiting to be discovered on a Friday afternoon by somebody else.
5. Delete what nothing uses now
Remove the fixture files, factory helpers and seed data no test references any more. Search for the names before deleting, then delete without ceremony.
6. Check you did not soften the suite
Break the behaviour on purpose and confirm the slimmed tests still go red. Shorter tests that no longer detect anything are a regression dressed as a cleanup.
Rules
- Do not hide a value the test asserts on inside a builder default. If the test is about an adult account, the age belongs in the test.
- Do not build a fixture framework larger than the code it sets up.
- Do not swap real setup for a mock purely to shorten it. A builder keeps what the test proves; a mock changes it.
- Do not seed an entire database for a test that reads one row.
- Do not keep a fixture because something might need it later. It can come back in one line when something does.