I deleted 5 helper functions from my test suite by making test data declarative
There's a pattern I've seen in almost every test suite: a create_test_user()
function. It builds a struct with sensible defaults so tests don't have to
construct one from scratch.
It starts small. Then it grows. After a year it has 7 parameters and you have to read its definition to understand any test that calls it — because you can't tell from the call site which arguments matter and which are just noise.
// What is arg 3? arg 5? Does this test care about created_at?
// You have to check.
let user = create_test_user(1, "alice", "admin", true, created_at, ...);
The fix I landed on: make the setup declarative and put it at the call site. Only declare what the test actually depends on. Let everything else be randomly generated.
fn role_based_access(
admin: User { role: "admin", ...everything else random },
viewer: User { role: "viewer", ...everything else random },
) {
// test only cares about role — and now that's obvious
}
This is what fixtura does for Rust. It's a small library built on top of fake-rs that wires up random struct generation and lets you override only the fields that matter for a given test.
The gains after migrating CILens, a CI analytics tool I built:
- Deleted 5 helper functions entirely
- Test suite shrank by 25%
- ~120 struct fields that were hardcoded for no reason are now faked freely
- Tests read like specifications: if a field isn't in the parameter list, the test doesn't depend on it
The broader principle works in any language: test setup should declare intent, not construction. The more a test hides in a helper, the harder it is to understand what the test is actually verifying.
https://github.com/dsalaza4/fixturaa (Rust-specific, but the idea isn't)