What makes a test independent of the other tests in its suite?
answer
- Would it still pass on its own?
- Three properties, not one
- Arrange it yourself, share nothing writable
- Leave the environment as you found it
- Buys shuffling, subsets and parallel runs
basics
~20 sAn independent test arranges everything it needs itself, writes to no state another test can observe, and leaves the environment as it found it. It gives the same verdict alone, in any position in the run, or beside tests on another worker.
solid answer
~40 sIndependence means a test's result never depends on which other tests ran, or in what order. Three properties produce it. First, **self-contained arrangement**: the test creates its own inputs rather than assuming a record, session or counter left by an earlier test. Second, **no observable shared mutable state**: it does not write to a module-level fixture, a cache, a static counter, a fixed identifier or a global setting that another test reads. Third, **cleanup**, so the next run starts where this one did. The payoff is practical rather than aesthetic: an independent suite can be shuffled, run as a subset around the module you just changed, and split across parallel workers, and when one test fails the failure names one behaviour instead of leaving you to ask whether something upstream wrecked the state.
code
pseudocode · 21 lines# coupled: the second test only passes if the first ran, and ran first
shared_booking = null
test "creates a booking":
shared_booking = service.create(guest: "ok", nights: 2)
assert shared_booking.status == "CONFIRMED"
test "cancels a booking":
result = service.cancel(shared_booking.id) # reads state test 1 left
assert result.status == "CANCELLED"
# independent: each test arranges what it asserts on
test "creates a booking":
booking = service.create(guest: "ok", nights: 2)
assert booking.status == "CONFIRMED"
test "cancels a booking":
booking = service.create(guest: "ok", nights: 2) # own arrangement
result = service.cancel(booking.id)
assert result.status == "CANCELLED"go deeper
Be ready to state the property in one sentence and give one concrete example of breaking it, such as a second test reading a record the first one created. Know that tests are not guaranteed to run in the order they appear.
Explain the three mechanics that produce independence — own arrangement, no writable shared state, cleanup — and name where shared state hides, especially setup that runs once per file rather than once per test.
Show you connect independence to operations: shuffled ordering in the pipeline, running a subset around a change, and splitting a long run across workers. Be able to say why a failing coupled test costs more to diagnose than to fix.
Own the tradeoff between per-test arrangement cost and suite runtime, and the rule you would set for shared immutable fixtures. Decide how the property is enforced so it does not decay, since coupling is always the locally cheaper choice for whoever is in a hurry.
**Independence** is a property of a single test measured against the rest of its suite: the test's result is the same whether it runs alone, first, last, or beside other tests on another worker. A suite in which every test has that property can be re-ordered, sliced into subsets, and spread across parallel workers without changing a single verdict. A suite in which some tests lack it has a hidden execution graph that nobody wrote down and nobody maintains. ### The three properties that add up to independence **1. Self-contained arrangement.** Everything the test needs to reach its starting state is created by the test itself, or by a setup hook that runs for that test. It never assumes a record, a file, a counter, a cached value or a logged-in session exists because an earlier test made one. The practical test: if you deleted every other test in the file, this one would still have the inputs it asserts on. **2. No observable shared mutable state.** The test writes only to state that no other test can read. Shared mutable state comes in more shapes than people expect: a module-level collection reused as a fixture, a singleton cache, a static counter, a fixed identifier such as a customer code that two tests both claim, a temporary directory with a hardcoded name, an altered runtime locale or time zone, a stubbed clock left frozen, a global configuration flag flipped in one test and never restored. Any of these turns two tests into one test with two entry points. **3. Cleanup that leaves the world as it was found.** The test undoes what it did, so a second run against the same environment starts from the same place as the first. This is why a suite can be order-independent and still not be *repeatable*: nothing depended on ordering within a run, but the run as a whole left residue that makes the next run behave differently. The specific mechanics for resetting a shared store are a discipline of their own; the property to understand here is simply that after the test, no other test's premises have changed. ### Why interviewers care Independence is not tidiness — it is what buys three concrete capabilities. *Any order.* The moment a suite can be shuffled, the runner is free to order tests for speed, and a newly added test cannot break an old one by being inserted above it. *Any subset.* Developers want to run the nine tests around the module they just changed. In a coupled suite those nine fail, not because the change is wrong but because the state they silently relied on was built by tests that were filtered out. Teams that hit this stop running subsets and start running everything, which is how a suite grows into an hours-long ritual nobody executes before pushing. *Parallel execution.* Splitting work across workers is the cheapest way to shorten a long run, and it is only safe when no two tests contend for the same mutable thing. There is a fourth, quieter benefit: **diagnosis**. When an independent test fails, the failure names one behaviour, and the fix is scoped to that behaviour. When a coupled test fails, the first question is always "did this test fail, or did something upstream fail and leave me the wreckage?" — and answering that question costs more than the fix. ### The tempting exception, and its one safe form Building a fresh fixture per test costs time, so teams share. The distinction that matters is **mutable versus immutable**. A fixture that is genuinely read-only for the whole run — a parsed reference table, a compiled schema definition, a set of static lookup codes nothing writes to — can be built once and shared without breaking independence, because no test can change what another test observes. The failure mode is a fixture that starts read-only and quietly acquires a writer six months later; from that commit onward the suite has an undocumented ordering constraint, and it usually surfaces as a case that fails only when the run is shuffled or split. ### The chained-test anti-pattern The most common breach is deliberate: a sequence such as *create the record*, then *update the record*, then *cancel the record*, written as three cases that must run in that order. It looks like three tests and reports as three tests, but it is one scenario with three checkpoints. If the first case fails, the other two fail for a reason that has nothing to do with what they were written to check, and the report claims three defects where there is one. If the scenario really is one journey worth testing end to end, express it as one test with intermediate assertions — one honest verdict for one scenario — rather than as a chain that lies about how many things are broken. ### How independence is enforced in practice Randomise or reverse execution order in the pipeline so a dependency is discovered by the build rather than by a developer at midnight; run any suspect test on its own; and treat a case that passes in the full run but fails alone as a defect in the test, not a curiosity to be worked around by pinning the order.
- Is it ever acceptable for tests to share one fixture object?Yes, when it is genuinely immutable for the whole run: a parsed reference table, a compiled schema definition, a set of static lookup codes nothing writes to. No test can change what another observes, so independence holds and you save the build cost. The risk is drift: a read-only fixture that quietly acquires a writer later creates an undocumented ordering constraint. Make the shared object unmodifiable so the first attempted write fails loudly instead of silently coupling two tests.
- A suite passes in any order but fails the second time it is run against the same environment. What is wrong?It is order-independent but not repeatable. Nothing depended on ordering within a run, yet the run left residue — records, files, a changed setting — so the second run no longer starts from the same premises. The usual culprit is a test that creates state and never removes it, or one that asserts a count from zero. Independence has to hold across runs as well as within one, which means cleanup, not just self-contained arrangement.
- Where does shared mutable state usually hide, apart from the test bodies?In setup that runs once for the whole file rather than once per test, because it reads like ordinary arrangement code while actually being a fixture that outlives every test. After that: singletons and caches, static counters, a stubbed clock left frozen, an altered runtime locale or time zone, a global configuration flag flipped and never restored, a temporary directory with a hardcoded name, and fixed identifiers that two tests both claim.
Each test should be a self-service kitchen station: you bring your own ingredients, cook on your own surface, and wipe it down. Sharing one chopping board means whoever cooks after you inherits your mess.
saying these in an interview costs you the question
- Thinks independence just means tests run fast
- Assumes tests always execute in declared file order
- Shares one mutable fixture object across the whole file
- Fixes an ordering failure by pinning the order
- Cleans up only in the success path
- Treats a global stubbed clock as harmless shared state