Skip to content

What is the difference between mocks, stubs, and fakes?

Mocks, stubs, and fakes are test doubles, stand-ins for real parts of a system that check calls, return canned answers, or work in a simpler way.

Last updated , 9 min read

What is the difference between mocks, stubs, and fakes?

Mocks, stubs, and fakes are three kinds of test double, an object that a test uses in place of a real component. A stub returns canned answers. A mock also checks that the code called it as expected. A fake is a working but simpler version of the component, e.g. an order store kept in memory.

The International Software Testing Qualifications Board (ISTQB) defines a test double as a replacement component that the item under test calls. Martin Fowler's Test Double page lists the five kinds that Gerard Meszaros named, which are dummies, fakes, stubs, spies, and mocks. ISTQB says a mock simulates expected behavior, while Meszaros defines a mock by the calls it expects.

In software testing, "mocking" usually means replacing any dependency with a double. Doubles keep a unit test fast and give it test isolation from shared databases. The cost is that the test checks the code against the double, not the real component.

How do mocks, stubs, and fakes compare?

The three kinds of double differ in what they do and in what a test can check through them:

QuestionStubMockFake
What does it do?Returns canned answersRecords calls and checks them against expectationsRuns a simpler working version
What does the test check?The result or state of the codeThe calls the code madeThe state left in the fake
Which verification style fits?State verificationBehavior verificationState verification
Where does it fit best?Inputs the code readsOutgoing calls that are the resultState the code saves and reads back
Can it fail the test by itself?NoYesOnly when it enforces a rule
What is its main risk?Its canned answer can differ from the real oneThe test breaks on harmless refactorsIt can drift from the real component

What is a stub?

A stub is a test double that returns fixed answers to the calls a test plans for, and does nothing else. It controls what the system under test, the code the test exercises, receives from a dependency. The test then checks the result, which Fowler calls state verification.

Acme Co. sells furniture online. This pytest test replaces its shipping rate service with a stub:

class StubRates:
    def rate_for(self, address):
        return 12.00  # the same answer for any address


def test_total_includes_shipping():
    checkout = Checkout(rates=StubRates())
    checkout.add_item("oak chair", price=114.00, quantity=2)
    assert checkout.total(address="12 Elm Street") == 240.00

A stub cannot fail the test by itself. If the code never asks for a rate, the stub stays silent, and only the assertion on the total catches the mistake.

What is a mock?

A mock is a test double that is set up with the calls it expects and fails the test when the actual calls do not match. Fowler's article Mocks Aren't Stubs calls this behavior verification. A mock fits an outgoing call that is itself the result, e.g. a confirmation email:

from unittest.mock import Mock


def test_order_sends_one_confirmation():
    mailer = Mock()
    checkout = Checkout(rates=StubRates(), mailer=mailer)
    checkout.place_order("A-1042")
    mailer.send_confirmation.assert_called_once_with("A-1042")

Python's unittest.mock checks the recorded calls after the code runs. By Meszaros's definitions, that double is a spy, but the library calls it a mock.

What are fakes, spies, and dummies?

Meszaros's vocabulary adds three kinds of double to stubs and mocks:

  • Fake. A fake has a working implementation with a shortcut, e.g. an order store that keeps orders in a Python dictionary. The test runs the code and then reads what the fake stored.
  • Spy. A spy is a stub that also records how it was called, so the test can check the calls afterward.
  • Dummy. A dummy is an object that a test passes only to fill a parameter list.

When should a team use a mock or a stub?

Here is an illustrative example. A developer at Acme asks a coding agent to "Let customers edit their delivery address during checkout." The agent writes a change_address function and a unit test with three doubles:

  1. The agent stubs the rate service, because the code reads a shipping price from it.
  2. The agent mocks the mailer, because the confirmation email is the result.
  3. The agent also mocks the order store and checks that update receives the edited address.
  4. The test passes. The real store's update resets any field it is not given, so the order loses its items.
  5. The address saved, but the cart emptied. The mock accepted the call because it has none of the store's behavior.
  6. A fake store with the same reset rule fails the second test below with assert 0 == 2.

The first test is the agent's, and the second uses a fake order store:

def test_change_address_updates_order():
    orders = Mock()
    mailer = Mock()
    change_address(orders, "A-1042", "12 Elm Street",
                   rates=StubRates(), mailer=mailer)
    orders.update.assert_called_once_with("A-1042", address="12 Elm Street")
    mailer.send_confirmation.assert_called_once_with("A-1042")


def test_change_address_keeps_items():
    orders = FakeOrderStore(order_id="A-1042", items=2)
    change_address(orders, "A-1042", "12 Elm Street",
                   rates=StubRates(), mailer=Mock())
    assert orders.get("A-1042").items == 2

Steps 1 and 2 follow a sound rule, which is to stub what the code reads and mock a call only when the call is the result. Step 3 breaks it, because the result of update is saved state, which needs a fake or the real component. This example is simplified. A real project would also check the fake store against the real one.

What changes when a coding agent writes the code?

A coding agent that writes both the code and its mocks generates them from the same prompt and context. The mock's expected call then often copies the call the agent's own code makes. In the Acme test, the code sends update only the address, so the assertion expects only the address. The test checks the code against a copy of itself, close to a tautological test that passes whether the code is right or wrong.

A bare Mock also accepts calls to methods that the real store does not have. If the code calls orders.save_address, the mock records the call, and an assertion copied from the code passes. The result is a false pass, which is one reason AI-written tests can pass on broken code.

A team can require a fake, with rules taken from the real component, for any component the change writes to. The team also keeps at least one end-to-end test per workflow that runs the real dependencies, in files the agent does not edit.

Can mocks, stubs, and fakes be used together?

One test can mix all three. A sound version of the Acme test stubs the rate service, mocks the mailer, and uses a fake order store.

Three test doubles in one test Stub returns a canned rate Checkout code system under test Mock checks the email call Fake stores orders in memory
The stub feeds input into the code, the mock checks what the code sends out, and the fake holds state. None of the three is the real component.

What are the limits of test doubles?

Doubles set three limits:

  • A double fails only in the ways its author planned. A plain mock accepts calls that the real component would reject.
  • A mock ties the test to the code's calls. A refactor that sends the same email another way fails the test.
  • A double can drift from the real component. When the real component changes its interface or its rules, tests against the old double keep passing.

Python's create_autospec makes a mock reject calls that do not match the real object's methods and signatures. That catches a changed interface, not a changed rule. A faithful fake or an integration test against the real order store would have caught the empty cart.

The classical style of test-driven development that Fowler describes uses real objects where it can and a double only where the real one is awkward, e.g. a mail service. The mockist style, often called the London school, uses a mock for most collaborators instead. Either way, only a test that runs the real store can catch the empty cart, which is why a suite also needs integration and end-to-end tests.

How do you catch failures the mocks hide?

Keep mocks at the edges, for outgoing calls that are the result, and check each fake against the real component. Treat a mock that an agent adds to a failing test as a sign that the test may now hide a failure. Then run the finished software with its real dependencies.

RunStory runs your software in a separate environment, tries relevant workflows, and checks the results. It sends reproducible failures to your coding agent and verifies the fix. It is in private alpha for CLIs and web apps.

Join the RunStory alpha →

FAQs

What is the difference between faking, mocking, and stubbing?

Faking, mocking, and stubbing differ in what the test checks. Stubbing sets the answers a double returns, and mocking sets the calls it expects and fails on a mismatch. Faking supplies a small working version whose saved state the test reads afterward.

How do you unit test without mocking everything?

Unit testing without mocking everything means using real objects where they are fast and repeatable, and a double only where the real one is awkward. Mocks then stay at the edges for outgoing calls, and a fake stands in for saved state.

Is there a point to tests that stub everything?

A test that stubs every dependency still checks the logic inside one unit, e.g. how a total uses a canned shipping rate. The test cannot show that the unit works with its real dependencies, so integration or end-to-end tests must cover that.

How do mocks hide dependency problems?

Mocks hide dependency problems because a mock returns what the test author expected, not what the real component does. When the real component rejects a call, changes its interface, or changes its rules, the mocked test can keep passing.