A unit test needs a 60-line setup block and its class takes eleven constructor parameters — what is that telling you about the design?
answer
- The test is a client that pays
- One measurement stated twice
- Look for collaborators that travel together
- Fix the production code, not the arrangement
- Side effects after a decision suggest a return value
basics
~20 sTest pain is design feedback. A long arrangement block and a wide constructor both report that the unit depends on too many things, so the fix belongs in the production code, not in a bigger setup helper.
solid answer
~50 sBoth symptoms are one measurement stated twice: this unit is coupled to eleven collaborators. The test is simply the first client that has to pay for it without framework wiring to hide the bill. In emergent design this is the signal that drives the next restructuring, and the useful move is to look for clumps — collaborators that are always constructed together and always used together are one missing concept, so extract it and pass one thing instead of four. Collaborators used only after an outcome is decided suggest the unit should return an outcome rather than perform side effects. The wrong responses all make the test comfortable and leave the design alone: a shared setup helper, a builder that hides the width, or standing in for everything so nothing has to be built. Do the extraction in the restructuring step, with the suite green.
code
pseudocode · 18 linesclass BidAcceptor(auctions, bids, clock, closeTimes, extendWindow,
fees, currencies, audit, notifier, limiter, metrics)
test "bid above the leader wins":
auctions = InMemoryAuctions()
bids = InMemoryBids()
clock = TestClock(at: "2026-04-11T10:14:03Z")
closeTimes = CloseTimeTable(default: "2026-04-11T10:15:00Z")
extend = ExtendWindow(seconds: 30)
fees = FlatFees(percent: 2.4)
currencies = FixedRates("EUR" -> 1.0)
audit = RecordingAudit()
notifier = SilentNotifier()
limiter = AllowAll()
metrics = NullMetrics()
acceptor = BidAcceptor(auctions, bids, clock, closeTimes, extend,
fees, currencies, audit, notifier, limiter, metrics)
# ... 40 more lines before the first assertiongo deeper
Recall the headline: when a test is hard to arrange, suspect the production code before you suspect the test. Know that a very wide constructor is a signal, and that hiding it behind a helper does not fix anything.
Explain the mapping from symptom to cause — long arrangement to too many collaborators, repeated groups to a missing concept, side-effect collaborators to a missing return value — and walk through one extraction that shrinks the constructor.
Show judgement about which pain is real: distinguish a genuinely stateful fixture from coupling, and describe how you keep the correction small and continuous rather than stopping delivery for a redesign.
Own the habit at team scale: how you make the cost curve of arrangement visible in review, and how you prevent test infrastructure from being built to absorb signals the design should have answered.
### Test pain is a measurement, not a chore The practice at issue is usually called **listening to the tests**: treating difficulty in writing or maintaining a test as data about the production design rather than as an inconvenience of testing. It matters in emergent design because the arrangement block is where the cost of a structure shows up first. A test is the earliest independent client of the unit; it has to build whatever the unit demands, with no framework wiring to hide the bill. So a long setup and a wide constructor are one observation stated twice: **this unit is coupled to that many things.** Sixty lines of arrangement do not mean the test is bad. They mean the design asks for sixty lines of context before it will do anything. ### The common signals and what each one reports | What hurts in the test | What the production code is telling you | | --- | --- | | Long arrangement, many collaborators built | The unit depends on too many things; responsibilities are clumped | | Several collaborators always constructed together | Those collaborators are one missing concept | | The test reaches through one object to set up another | The unit reaches too; the dependency is transitive and hidden | | You must assert on internals to see the effect | The behaviour has no observable outcome; the interface is wrong | | A combinatorial blow-up of cases | One unit is making several independent decisions | | Setup grows every time any feature is added | The unit is a hub everything must be threaded through | ### The wrong responses Almost every wrong answer here consists of making the *test* more comfortable while leaving the design exactly as it was: * a shared setup helper that builds the eleven collaborators once for the whole file — now the coupling is real and invisible, and one change to it ripples through every case; * a builder whose only job is to hide the width of the constructor; * standing in for every collaborator so nothing has to be built — the count of stand-ins is itself the measurement, and hiding it discards the signal; * declaring the class "just wiring, framework requires it" when nothing about the framework required eleven parameters. The right response puts the change in the production code, and emergent design says exactly when to make it: in the restructuring beat, with the suite green. ### A worked example In a marketplace bidding engine, `BidAcceptor` accumulates eleven constructor parameters — auction store, bid store, clock, fee schedule, currency converter, audit writer, notifier, rate limiter, fraud score client, feature flags, metrics. Its unit test needs 63 lines before it can assert that a bid 40 cents above the leader wins. Reading the clumps: the clock, the close time and the extend window always appear together and are only ever used to answer "is this bid in time" — that is an auction-clock concept. The audit writer, the notifier and the metrics recorder are always used *after* an outcome is decided — that is one outcome-publication role, and the acceptor should return an outcome rather than perform three side effects. The fee schedule and the currency converter are only used to price the bid — a pricing collaborator. After those three extractions the acceptor takes four parameters, its test arranges in nine lines, and the three new units have their own small tests. Nothing was designed up front: the clumps were visible only because eleven parameters had accumulated one test at a time. ### Why the interviewer asks Because it separates two attitudes. One treats tests as an obligation that gets more expensive as the system grows, so the answer is better test infrastructure. The other treats the cost curve of the tests as the cheapest available reading on the design, and answers by changing the design. The second attitude is what makes emergent design work at all: without it, the signals arrive and get absorbed by helpers. ### Caveats worth voicing Not every long setup is a design defect. Genuinely stateful domains need real fixtures, and a test at a coarser level legitimately arranges more than a unit test does. The signal is *the trend and the clumping*, not the raw line count: setup that grows monotonically, or the same group of collaborators appearing together in every case, is the part that reports coupling. And the response is always a small restructuring under a green suite — you do not stop delivering to redesign, because the whole point is that this correction is cheap when taken early.
- When is a long arrangement block not a design defect?When the domain is genuinely stateful and the scenario needs real data, or when the test sits at a coarser level than a unit test and legitimately arranges more of the system. The signal is the trend and the clumping, not the raw line count: arrangement that grows every time any feature is added, or the same group of collaborators appearing together in every case, is what reports coupling. A one-off large but flat fixture is usually fine.
- Why is a shared setup helper the wrong first response to this?Because it hides the measurement without changing what it measured. The unit still depends on eleven things; now the dependency is expressed once, invisibly, and every case in the file is coupled to that one arrangement. A change to any collaborator ripples through every test, and the growth signal you were relying on to drive the next restructuring is gone.
- How do you decide which clump to extract first when several are visible?Take the one with the clearest name in domain language and the tightest usage — collaborators that are always constructed together and used together in one place. Extracting a well-named clump shrinks the constructor and gives you a unit with its own small test. Leave clusters you cannot name yet; an extraction you cannot name is usually the wrong seam and will have to be undone.
saying these in an interview costs you the question
- Fixes long arrangement with a bigger shared setup helper
- Adds a builder to hide eleven parameters rather than remove them
- Says test pain is just the unavoidable cost of testing
- Stands in for every collaborator so nothing is built
- Calls the wide constructor unavoidable framework wiring
- Rewrites the test as an end-to-end case to skip the arrangement