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 MockingTest 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 StubMocking and Test Stub compared
| Aspect | Mocking | Test Stub |
|---|---|---|
| Purpose | Checks that the code made the right calls | Feeds the code the data it needs to run |
| What the test asserts | Calls to the mock: which ones, how often, with what arguments | The result or state of the code under test |
| Verification style | Behavior verification | State verification |
| Can fail the test | Yes, when expected calls are missing or wrong | No; it only returns answers |
| Coupling to implementation | Higher: changing how the code works can break the test | Lower: only the outcome is checked |
| Typical use | Commands with side effects: send an email, charge a card, publish an event | Queries: an exchange rate, a user record, the current date, an error |
| In libraries | toHaveBeenCalledWith in Jest, verify(...) in Mockito | mockReturnValue 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
// 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!");
});// 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.