Cleanup, Fake Timers & Testing Tradeoffs
Restoring & Sandboxes
const sandbox = sinon.createSandbox()
afterEach(() => {
sandbox.restore() // restores every fake created via sandbox.stub/spy/mock
})
it('does something', () => {
const stub = sandbox.stub(db, 'query').resolves([])
// ...
})Failing to restore a stub on a shared object is a classic source of test pollution — the fake behavior can leak into and break later, unrelated tests. Sandboxes group multiple fakes so a single afterEach restore() call cleans them all up reliably.
Fake Timers
const clock = sinon.useFakeTimers(new Date('2026-01-01'))
scheduleReminder() // internally uses setTimeout
clock.tick(60 * 60 * 1000) // advance 1 hour instantly
sinon.assert.calledOnce(reminderCallback)
clock.restore()useFakeTimers replaces setTimeout, setInterval, and Date with controllable fakes — tests advance simulated time instantly and deterministically instead of waiting on real delays or depending on the actual current time, eliminating a whole class of flaky, timing-dependent test failures.
createStubInstance & sinon.fake
createStubInstance(SomeClass) produces a fake with every method pre-stubbed, avoiding manual per-method setup for class-shaped dependencies. The newer sinon.fake() API offers a more minimal alternative for common faking needs without the full spy/stub/mock surface.
The Overuse Tradeoff
Stubbing an external dependency (database, HTTP call) makes unit tests fast, deterministic, and independent of network/database availability. But excessive mocking can couple tests tightly to implementation details and hide real integration bugs that only appear when components actually interact — worth balancing with some integration/end-to-end coverage that exercises real interactions.
Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free