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)