Skip to content

Error Handling in Mocks ​

Mocks have strict verification requirements and will throw errors when expectations aren't met or when used incorrectly. Understanding these errors is essential for effective mock usage.

Null or Undefined Object ​

Attempting to create a mock for a null or undefined object will fail.

javascript
// This will throw: "object is null"
sinon.mock(null);
sinon.mock(undefined);

Solution: Provide a valid object:

javascript
const obj = { method() {} };
const mock = sinon.mock(obj);

Falsy Method Name ​

Setting an expectation on a falsy method name will fail.

javascript
const mock = sinon.mock(obj);

// This will throw: "method is falsy"
mock.expects(null);
mock.expects(undefined);
mock.expects("");

Solution: Provide a valid method name:

javascript
mock.expects("validMethodName");

Unmet Expectations ​

The most common mock error: calling verify() when expectations aren't met.

javascript
const obj = { greet() {} };
const mock = sinon.mock(obj);

mock.expects("greet").once();
// greet is never called

mock.verify(); // Throws: "Expected greet(...) once (never called)"

Error message includes:

  • Which expectation failed
  • How many times it was expected
  • How many times it was actually called

Solution: Ensure all expectations are met:

javascript
const obj = { greet() {} };
const mock = sinon.mock(obj);

mock.expects("greet").once();
obj.greet(); // Call the method
mock.verify(); // Now succeeds

Unexpected Calls ​

Calling a mocked method in a way that doesn't match any expectations will fail immediately.

javascript
const obj = { greet(name) {} };
const mock = sinon.mock(obj);

mock.expects("greet").withExactArgs("Alice");

// This throws immediately: "Unexpected call: greet(Bob)"
obj.greet("Bob");

Error message includes:

  • The unexpected call details
  • All defined expectations
  • Stack trace for debugging

Solution: Either adjust the expectation or fix the call:

javascript
// Option 1: Use withArgs instead of withExactArgs
mock.expects("greet").withArgs("Alice"); // Also accepts more args

// Option 2: Match the expectation exactly
obj.greet("Alice"); // Now matches

// Option 3: Add multiple expectations
mock.expects("greet").withExactArgs("Alice");
mock.expects("greet").withExactArgs("Bob");

Verify Auto-Restores ​

An important behavior: mock.verify() automatically calls mock.restore().

javascript
const obj = {
  method() {
    return "original";
  }
};
const mock = sinon.mock(obj);

mock.expects("method").once();
obj.method();

mock.verify(); // Verifies AND restores

// Method is now restored
obj.method(); // Returns 'original', not a mock

This is by design. The expectation is that verify is your last action with the mock.

Problem: Calling verify() twice will fail on the second call:

javascript
mock.verify(); // First call succeeds and restores
mock.verify(); // Second call throws - mock is already restored

Solution: Only call verify() once per mock, typically in test cleanup:

javascript
afterEach(() => {
  mock.verify(); // Verify once at the end
});

Overwriting Expectations ​

Setting multiple expectations with withArgs() or withExactArgs() on the same expectation will overwrite previous arguments.

javascript
const mock = sinon.mock(obj);
const expectation = mock.expects("method");

expectation.withArgs("first");
expectation.withArgs("second"); // Overwrites 'first'

obj.method("first"); // Fails! Expectation now requires 'second'

This is documented behavior: An expectation holds only one set of arguments.

Solution: Create multiple expectations for different arguments:

javascript
const mock = sinon.mock(obj);
mock.expects("method").withArgs("first");
mock.expects("method").withArgs("second");

obj.method("first"); // Matches first expectation
obj.method("second"); // Matches second expectation

Too Many Calls ​

Calling a method more times than expected will fail.

javascript
const mock = sinon.mock(obj);
mock.expects("method").once();

obj.method(); // OK
obj.method(); // Throws: "Unexpected call: method()"

Solution: Adjust expectation or use atLeast():

javascript
// Option 1: Set correct count
mock.expects("method").twice();

// Option 2: Use atLeast for minimum
mock.expects("method").atLeast(1); // Allows 1 or more

// Option 3: Use atMost for maximum
mock.expects("method").atMost(2); // Allows 0, 1, or 2

Debugging Mock Failures ​

When mock expectations fail, the error messages can be dense. Here's how to read them:

javascript
Error: Expected greet('[...]') once (never called)
    greet(Bob) at MyTest.js:15

Reading the error:

  1. "Expected greet('[...]') once" - The expectation
  2. "(never called)" - What actually happened
  3. "greet(Bob) at MyTest.js:15" - Stack trace of unexpected calls (if any)

Debugging steps:

  1. Check the expectation: Is it correct?
  2. Check the actual calls: Are they happening?
  3. Check the arguments: Do they match?
  4. Check the call count: Right number of calls?

Best Practices ​

  1. One mock per test - Multiple mocks make failures hard to diagnose
  2. Verify once - Call verify() only once, in cleanup
  3. Expect only what matters - Don't mock what you don't need to verify
  4. Use explicit assertions - Consider fakes + assertions instead of mocks
  5. Test behavior, not implementation - Avoid coupling tests to internal calls
  6. Clear error messages - Use descriptive method names in tests

Common Pitfalls ​

Testing Implementation Details ​

javascript
// BAD: Testing how the code works internally
mock.expects("_privateMethod").once();
mock.expects("helperFunction").twice();

// GOOD: Testing what the code does
const fake = sinon.fake.returns("result");
sinon.replace(obj, "publicMethod", fake);
// Assert on behavior, not internal calls

Too Many Expectations ​

javascript
// BAD: Every interaction is an expectation
mock.expects("log").atLeast(1);
mock.expects("validateInput").once();
mock.expects("processData").once();
mock.expects("sendResponse").once();

// GOOD: Only mock what you need to control or verify
const fake = sinon.fake.resolves("result");
sinon.replace(service, "getData", fake);
// Explicit assertions on behavior
assert.ok(fake.called);

Brittle Tests ​

javascript
// BAD: Test breaks when call order changes
mock.expects("a").once();
mock.expects("b").once();
mock.expects("c").once();
// Now code must call in exact order: a, b, c

// GOOD: Test the outcome, not the path
const result = await service.process();
assert.equal(result, expectedValue);

See Also ​