Skip to main content

Side by side

MockingvsTest Stub

What is the difference between a mock and a stub?

Updated 3 min read7 differences

In short

A stub returns canned answers so the code under test can run; a mock also checks how it was called, so the test fails if the expected calls didn't happen.

Mocking

Mocking is a testing technique that replaces a real dependency, such as a database or API, with a fake you control so that code can be tested in isolation.

Read the page on Mocking

Test Stub

A test stub is a stand-in for a real dependency that returns prepared answers during a test, so code can be tested without the real database or service.

Read the page on Test Stub

Mocking and Test Stub compared

AspectMockingTest Stub
PurposeChecks that the code made the right callsFeeds the code the data it needs to run
What the test assertsCalls to the mock: which ones, how often, with what argumentsThe result or state of the code under test
Verification styleBehavior verificationState verification
Can fail the testYes, when expected calls are missing or wrongNo; it only returns answers
Coupling to implementationHigher: changing how the code works can break the testLower: only the outcome is checked
Typical useCommands with side effects: send an email, charge a card, publish an eventQueries: an exchange rate, a user record, the current date, an error
In librariestoHaveBeenCalledWith in Jest, verify(...) in MockitomockReturnValue in Jest, when(...).thenReturn(...) in Mockito

The difference, explained

Mocks and stubs are both test doubles: stand-ins for a real dependency, such as a database, a payment API or the clock, that make a test fast and predictable. A stub only supplies answers: when the code asks for an exchange rate, it returns 0.9, and the test then checks what the code did with it. A mock is programmed with answers too, but it also records its calls and carries expectations about them, such as sendEmail being called once with the right address.

The essential difference is what the test verifies. With a stub, the test asserts on the result or the state of the code under test, which Martin Fowler calls state verification, and the stub never fails a test on its own. With a mock, the test asserts on the interaction itself, which he calls behavior verification, and that is the only way to check outcomes that are calls, such as sending an email or charging a card. The vocabulary most people use comes from Gerard Meszaros's 2007 book xUnit Test Patterns, which names five kinds of test double: dummy, stub, spy, mock and fake.

Most test suites use both, and libraries blur the names. Jest, Sinon, Mockito and Python's unittest.mock create objects that can act as either: mockReturnValue or when(...).thenReturn(...) makes a stub, and asserting with toHaveBeenCalledWith or verify(...) makes it a mock. A common pattern is to stub the queries the code needs and mock only the one command whose call is the point of the test.

A common misconception is that every fake object is a mock. Calling everything a mock hides the choice that matters: checking calls ties a test to how the code works, so it breaks when the implementation changes even though the behavior didn't. Prefer stubs when only the outcome matters, and keep mocks for interactions that are themselves the requirement.

Which one should you use?

Choose Mocking when…

  • The outcome you care about is a call to another system, such as sending an email.
  • There is no return value or state to check, only a side effect.
  • You must prove that something did not happen, such as a card being charged twice.

Choose Test Stub when…

  • The code under test needs data from a slow, costly or unreliable dependency.
  • You want to simulate a specific answer, such as an error, a timeout or an empty list.
  • Only the result matters, and the test should survive refactoring.

The same Jest tools, used as a mock and as a stub

Mockingjavascript
// Mock: the test checks how the dependency was called
test("sends a welcome email", async () => {
  const mailer = { send: jest.fn() };

  await registerUser({ email: "ada@example.com" }, mailer);

  expect(mailer.send).toHaveBeenCalledTimes(1);
  expect(mailer.send).toHaveBeenCalledWith("ada@example.com", "Welcome!");
});
Test Stubjavascript
// Stub: the dependency only returns a canned answer
test("converts dollars to euros", () => {
  const rates = { getRate: jest.fn().mockReturnValue(0.9) };

  const result = toEuros(100, rates);

  expect(result).toBe(90); // the test checks the result, not the calls
});

Readers ask

Is a stub a type of mock?

Both are types of test double, the general term for any stand-in used in tests. Many libraries call every double a mock, but strictly a stub only returns answers, while a mock also verifies its calls.

What is the difference between a mock and a spy?

A spy records how it was called, and the test checks those calls afterwards; a classic mock is set up with expectations in advance and verifies them itself. In Jest and Sinon the two are nearly the same, and jest.spyOn can also wrap a real method so that it still runs.

Should I use mocks or stubs?

Start with stubs and assert on results, since such tests survive refactoring. Use a mock when the call itself is the requirement, such as an email that must be sent, and avoid checking calls that are only internal steps of the code.

More

Settings