Why should a test that generates random data record and print the seed it used?
answer
- A failure nobody can repeat
- Which values did this run choose?
- One number regenerates the whole input
- Print it where failures are read
- Derive per case, not one stream
basics
~20 sRandom data makes a failure depend on values nobody chose. Recording the seed and printing it in the failure output lets anyone re-run the identical values, so the failure can be reproduced and fixed instead of guessed at.
solid answer
~50 sAn unseeded generator produces different values on every run, so a failure that appeared once may never appear again, and a defect you cannot reproduce is one you cannot diagnose or prove fixed. Seed the generator from a value the run chooses explicitly, print that value in the failure output, and accept it back as a parameter so re-running with it rebuilds the exact inputs. Prefer deriving each case's seed from the run seed plus a stable case identifier rather than sharing one generator: cases then stay independent, so a filtered, reordered or parallel run still reproduces case by case. A single hardcoded seed is fully reproducible but explores one point forever; a fresh printed seed explores more, but only if the value reaches the stored report and not just the console of the machine that produced it.
code
pseudocode · 13 linesrunSeed = parameter("seed") or pickUnpredictableValue()
report.header("run seed = " + runSeed)
function generatorFor(caseName):
return newGenerator(combine(runSeed, caseName))
function runCase(caseName, body):
rng = generatorFor(caseName)
try:
body(rng)
catch failure:
failure.attach("reproduce with: --seed " + runSeed + " --case " + caseName)
raise failurego deeper
Be ready to say why an unseeded generator makes a failure hard to fix, and to point at where the seed should be printed so a teammate can repeat the identical run.
Explain the mechanics: the run choosing one seed, each case deriving its own generator from it plus the case name, and why a shared stream makes values depend on execution order.
Show the triage habit: the seed carried into the stored result, a failing seed promoted into a permanent pinned case, and a rule for what happens when a seeded failure still will not reproduce.
Own the estate rule: which suites may vary their seed at all, who is funded to triage what variation produces, and the requirement that a defect arrives with a reproducing pinned case attached.
## The input nobody chose A test that builds its data from a random generator has an input that no one wrote down. The assertion still describes the behaviour under test, but the values that reached it came from a stream of numbers produced at run time. When such a case passes, nothing is lost. When it fails, the report says the behaviour was wrong for *some* input and offers no way to get that input back. Reproducibility is the whole point of a seed. A pseudorandom generator is deterministic: given the same starting value — the seed — it produces exactly the same sequence, every time, on every machine. The entire generated input of a run therefore collapses to one number. Record that number and the run is replayable; discard it and the run was a one-off experiment whose conditions are gone. ## Choose the seed, print the seed, accept the seed Three obligations, and a suite that meets all three is reproducible. **Choose it explicitly.** The run picks a seed and holds it, instead of letting each generator seed itself from something ambient. A generator that seeds itself and never announces the value is the worst case: the value existed, it determined everything, and nobody can read it. **Print it where failures are read.** Not on the console of a passing run, but in the failure message, in the machine-readable result file, and in the run summary artefact that outlives the machine. Triage usually starts from a stored report days later, on a different machine, by someone who was not watching. **Accept it back.** One parameter re-runs the suite, or one case, with a given seed. If replaying requires editing source, nobody will replay — they will rerun and hope for green. ## Per-case derivation, not one shared stream The naive implementation seeds one generator at start-up and lets every case draw from it. That reproduces the whole run in its original order and nothing else. Case forty-one's values depend on how many draws the previous forty cases made, so a filtered run, a reordered run or a parallel run hands case forty-one different data even under the same run seed — and the seed you carefully printed no longer reproduces the failure you are chasing. The fix is a derivation. Each case gets its own generator, seeded from the run seed combined with a stable identifier for the case: its name, not its position in the run. "Case *X* with run seed *S*" then becomes a complete reproduction recipe that survives filtering, reordering and parallel execution. ## A hardcoded seed or a fresh one? Both are defensible; they trade different things. A **hardcoded constant seed** makes the suite fully deterministic: identical values on every run, forever. Failures are reproducible by definition and the suite never turns red for a new reason. The cost is that the generated data has quietly become a fixture nobody chose deliberately — one point in a large input space, frozen on the day it was written. The suite stops finding anything new. A **fresh seed each run**, printed, covers more ground over time. The cost is triage: a failure can arrive on any morning, from values nobody has seen, and to anyone who does not know to read the seed it looks exactly like flakiness. That cost is only payable when the reporting obligations above are genuinely met. A common middle path is to run the blocking suite pinned, and to promote every seed that ever produced a failure into a permanent case with that seed written into it and a name saying what it caught. Over a year the pinned set becomes a record of the defects the code has actually had. ## A worked example A fleet telematics ingest has a suite that builds synthetic position reports for a batch of vehicles. Run 4,417 fails one case: the batch summariser loses a vehicle. The run printed its seed, 8413927, and the case derives its generator from that seed plus the case name, so re-running that single case with the same seed rebuilds the identical 1,243 reports and fails identically. The cause turns out to be a duplicate device identifier that the generator emits roughly once in several thousand draws. Now picture the same defect without a recorded seed: one red case, once in sixty-three runs, green on rerun. That is indistinguishable from an infrastructure hiccup, and it gets quarantined. Unrecorded randomness does not merely make defects hard to fix — it disguises them as something else. ## What a seed does not buy you A seed makes a run repeatable. It does not make the generated data representative, does not tell you which region of the input space you have visited, and does not turn a green run into evidence of correctness. It removes exactly one failure mode, irreproducibility, and that is enough to justify it, because every other kind of analysis depends on being able to run the same thing twice.
- What is the drawback of writing one constant seed into the suite and never changing it?The suite becomes fully deterministic but explores a single point in the input space forever. The generated values turn into a fixture nobody chose deliberately, and after the day it is written the generator finds nothing new. It is a reasonable default for a blocking suite, provided some other run varies the seed and every seed that ever failed is kept as its own pinned case.
- A parallel run reorders cases. Why can one shared generator make a failure unreproducible even when the seed was printed?Because each case's values depend on how many draws preceded it in the shared stream. Change the order, filter the run, or split it across workers and the same run seed hands a given case entirely different data. Deriving an independent generator per case from the run seed plus the case name removes the dependency on order.
- Besides the console, where must the seed appear?In the failure output itself, in the machine-readable result file, and in the run summary that is stored as an artefact. Triage usually happens later, from the stored report, on a machine that no longer exists in the same state. A seed that lives only in scrollback is a seed that will not be there when someone needs it.
The seed is the recipe number. Throw it away and you can still taste that the dish came out wrong, but you can never cook that same dish again.
saying these in an interview costs you the question
- Calls a random failure flaky and just reruns it
- Seeds from the current time and records nothing
- Prints the seed only when the run passes
- Uses one shared global generator for every case
- Claims a hardcoded seed makes the suite thorough
- Reconstructs the inputs by guessing from the assertion text