---
title: "Mock vs stub: differences and testing examples | Speedscale"
description: "A stub supplies responses; a mock verifies interactions. Compare both with runnable Python examples and learn when API traffic mocks help."
canonical: "https://speedscale.com/blog/mock-vs-stub/"
---

![Mock vs stub: differences and testing examples](https://speedscale.com/_astro/featured-image.dmYTcD-O_Z1DfyHG.webp)

# Mock vs stub: differences and testing examples

Jan 16, 2026 (Updated: Oct 12, 2026 )

[By Nate Lee](https://speedscale.com/blog/author/nate-lee/)

[Service Mocking](https://speedscale.com/blog/category/service-mocking/)

* * *

A **stub** supplies a response so a test can exercise another component. A **mock** verifies an interaction, such as whether a payment method received the expected amount. Use a stub when the result matters; use a mock when the interaction itself is part of the requirement.

The names get confusing because one library can do both. Python’s `unittest.mock.Mock`, for example, can return a canned value and record calls. An API mock server can also combine response stubbing with request verification. Look at what the test asserts before deciding which term describes it.

## Mock vs stub at a glance

| Question | Stub | Mock |
| --- | --- | --- |
| What does it supply? | A controlled response | A controlled dependency with recorded interactions |
| What does the test usually assert? | The application’s output or state | Arguments, call count, or another required interaction |
| Example | Return a declined payment response | Verify that a charge uses the expected amount |
| What can make the test brittle? | Fixtures that no longer match the real dependency | Assertions about incidental implementation details |

This follows the distinction between state verification and behavior verification described in Martin Fowler’s [Mocks Aren’t Stubs](https://martinfowler.com/articles/mocksArentStubs.html). A stub can vary its response by input or throw an exception. Returning the same value every time isn’t what defines it.

## A runnable example using the same dependency

Suppose a checkout function charges a payment gateway and returns a confirmation. Save this example as `test_checkout.py`. It uses Python’s standard library, so no test framework installation is needed.

```
import unittest
from unittest.mock import Mock


def checkout(gateway, total_cents):
    payment = gateway.charge(total_cents)
    return {"paid": payment["status"] == "approved"}


class CheckoutTests(unittest.TestCase):
    def test_confirmation_from_stubbed_response(self):
        gateway = Mock()
        gateway.charge.return_value = {"status": "approved"}
        result = checkout(gateway, 2500)
        self.assertEqual(result, {"paid": True})

    def test_charge_interaction(self):
        gateway = Mock()
        gateway.charge.return_value = {"status": "approved"}
        checkout(gateway, 2500)
        gateway.charge.assert_called_once_with(2500)


if __name__ == "__main__":
    unittest.main()
```

Run it with `python3 test_checkout.py`. The first test checks an application result using a stubbed response. The second checks the payment interaction. Both use a `Mock` object, but their assertions test different requirements.

Now change `gateway.charge(total_cents)` to `gateway.charge(1)`. The first test still passes because its configured response doesn’t depend on the amount. The second fails because the wrong amount reached the payment gateway. That failure is useful: the amount is part of the checkout contract.

An assertion that an internal helper ran exactly once might be less useful. If you refactor the helper while preserving payment behavior, that assertion can fail even though checkout still works. Keep interaction assertions tied to requirements callers depend on.

## When should you use a stub?

Use a stub to put the application into a specific condition. A declined card, an empty search result, or a dependency timeout can be difficult to reproduce on demand against a live service. A stub makes the condition repeatable.

For the checkout example, set the gateway response to `{"status": "declined"}` and assert that checkout returns `{"paid": False}`. The test can focus on the decision the application makes after receiving that response.

Keep the fixture small enough to understand. If the handler reads only a status field, a unit test may need only that field. An integration test should also exercise the response shape the dependency actually sends, including optional fields and error bodies. Those tests answer different questions.

## When should you use a mock?

Use a mock when the application must perform a particular interaction. A payment should use the correct amount. An email should go to the intended recipient. A failed operation might need to avoid writing a success record.

Assert the arguments or behavior that express that requirement. Avoid specifying every call the implementation makes. Otherwise, a routine refactor turns into a rewrite of tests that were meant to protect external behavior.

A passing interaction assertion doesn’t prove the real integration works. Your mock may accept a request the real API rejects. Keep contract checks or integration tests alongside these unit tests.

## API mock servers and recorded responses

Across a network boundary, a mock server returns responses over HTTP or another protocol. Some tools also verify the requests they received. That broader use of “mock” explains why an API mock server may mostly serve what a unit-testing article calls stubs.

[WireMock and MockServer](https://speedscale.com/blog/wiremock-vs-mockserver-vs-proxymock/) let you define HTTP responses and verify requests. With [proxymock](https://speedscale.com/proxymock/), you can record dependency requests and responses, then use that traffic to supply responses during later tests. Recorded traffic gives you fixtures based on observed behavior rather than a response shape guessed from memory.

The recording still needs review. Mask sensitive values before sharing it, update it when the dependency contract changes, and decide how unmatched requests should behave. proxymock’s default passthrough can reach a real dependency; use its documented `--no-passthrough` option when your test must stay isolated.

Start with the [proxymock quickstart](https://docs.speedscale.com/proxymock/getting-started/quickstart/) for API dependency mocks. For testing a complete code change, follow the [traffic replay walkthrough](https://speedscale.com/blog/test-ai-code-with-traffic-replay/), which preserves a working baseline and compares the changed application’s responses.

## Frequently asked questions

### What is the difference between a mock and a stub?

A stub supplies a controlled response. A mock verifies an expected interaction with a dependency. One test-double library can support both uses.

### Can a mock return a stubbed response?

Yes. A mock object can return configured responses and record calls. The assertions determine whether the test checks application output, interactions, or both.

### Are mocks better than stubs?

Choose based on the requirement. Use response stubbing to test outcomes under controlled conditions and interaction verification when a dependency call is part of the contract.

### What is the difference between a unit-test mock and an API mock server?

A unit-test mock replaces an object inside a process. An API mock server supplies responses across a network boundary and may also verify received requests.

## Table of Contents

## Stop writing API mocks by hand

proxymock records real traffic from your running app and replays it as mocks — HTTP, gRPC, Postgres, Kafka, and more. Install in 30 seconds, no account required.

[Install proxymock](https://docs.speedscale.com/proxymock/getting-started/installation/) [View the docs](https://docs.speedscale.com/proxymock/)
