Sinon
01 / 02

Spies, Stubs & Mocks

Spies, Stubs & Mocks

A Test-Double Library, Not a Test Runner

Sinon.js provides test spies, stubs, and mocks for JavaScript — it's paired with a test runner (Mocha, Jest, Jasmine) rather than replacing one, and often combined with an assertion library like Chai for general-purpose value assertions.

Spies — Watch Without Changing Behavior

const spy = sinon.spy(logger, 'warn')
doSomething()
sinon.assert.calledOnce(spy)
sinon.assert.calledWith(spy, 'unexpected input')
spy.restore()

A spy wraps an existing function, recording calls/arguments/return values while (by default) still calling through to the original implementation — useful for asserting "was this called correctly" without altering behavior.

Stubs — Replace With Controlled Behavior

const stub = sinon.stub(api, 'fetchUser')
stub.resolves({ id: 1, name: 'Alice' })
stub.onFirstCall().rejects(new Error('timeout'))

// later
stub.restore()

A stub replaces the real implementation entirely so tests can control what a dependency does — resolves/rejects simulate async outcomes without manual Promise plumbing, and onFirstCall/onSecondCall let a single stub behave differently across successive calls (e.g. testing retry logic).

Mocks — Behavior Plus Expectations

A mock combines stub-like replaced behavior with built-in expectations set up front ("expects this call exactly once with these arguments"), verified as a unit via .verify() — contrasted with stubs, which are typically asserted on individually after the fact.

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free