100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Python

Mocking and Test Doubles

Learn the five canonical test double types—dummy, stub, spy, mock, and fake—and how to use unittest.mock in Python.

Software TestingIntermediate11 min readJul 8, 2026
Analogies

Introduction

When a unit test needs to isolate the code under test from a slow, unreliable, or hard-to-set-up dependency — like a network call, a database, or the current time — it replaces that dependency with a 'test double': a stand-in object that behaves predictably for the purposes of the test. Test doubles are what make it possible to unit test code that would otherwise require a live external system.

🏏

Cricket analogy: A batting coach practices a player's cover drive against a bowling machine set to a fixed line and length instead of a live express bowler like Bumrah, isolating the technique from unpredictable real conditions.

Explanation

There are five canonical kinds of test doubles, and it helps to distinguish them by purpose. A dummy is an object passed in only to satisfy a parameter list; it is never actually used by the code under test, such as passing None or a placeholder object where an argument is required but irrelevant. A stub provides canned answers to calls made during the test, returning fixed, predetermined data regardless of input — useful for controlling what a dependency 'says' without checking how it was called. A spy is like a stub but also records information about how it was called (arguments, call count), so the test can later assert on that interaction history. A mock is a spy that also has pre-programmed expectations about how it should be called, and the test explicitly verifies those expectations were met — mocks are 'verified' as part of the test itself. A fake is a working, simplified implementation of a dependency, such as an in-memory database used instead of a real one; it behaves correctly but takes a shortcut unsuitable for production, such as no persistence to disk.

🏏

Cricket analogy: In nets, a throw-down assistant lobs balls just to fill the session (a dummy), a bowling machine repeats the same delivery (a stub), a coach with a clicker counts every shot type (a spy), and a coach who checks the batter hit exactly ten cover drives as planned (a mock) differ from a net bowler genuinely bowling variations that behave like a real match (a fake).

In Python, the unittest.mock module provides Mock and MagicMock objects that can act as stubs, spies, or mocks depending on how they're used, and the patch() function temporarily replaces a real object (like a module attribute or class method) with a Mock for the duration of a test.

🏏

Cricket analogy: The BCCI's official practice-match rulebook lets a team temporarily swap its real opponent for a specified 'shadow XI' for the duration of a training session, exactly as patch() temporarily swaps a real object for a Mock.

Example

python
from unittest.mock import Mock, patch


# Code under test: it depends on an external payment gateway.
class OrderProcessor:
    def __init__(self, payment_gateway):
        self.payment_gateway = payment_gateway

    def checkout(self, amount):
        result = self.payment_gateway.charge(amount)
        return result["status"] == "success"


# Using Mock() as a stub/spy: we control its return value and later
# inspect how it was called.
def test_checkout_returns_true_on_successful_payment():
    # Arrange: a Mock stands in for the real payment gateway
    fake_gateway = Mock()
    fake_gateway.charge.return_value = {"status": "success"}
    processor = OrderProcessor(payment_gateway=fake_gateway)

    # Act
    result = processor.checkout(100)

    # Assert: check the behavior AND how the mock was used
    assert result is True
    fake_gateway.charge.assert_called_once_with(100)


# Using patch() to replace a real dependency during a test.
class ReportGenerator:
    def build_filename(self):
        import datetime
        today = datetime.date.today()
        return f"report-{today.isoformat()}.csv"


@patch("datetime.date")
def test_build_filename_uses_todays_date(mock_date):
    # Arrange: force datetime.date.today() to return a fixed value
    import datetime
    mock_date.today.return_value = datetime.date(2024, 1, 1)
    generator = ReportGenerator()

    # Act
    filename = generator.build_filename()

    # Assert
    assert filename == "report-2024-01-01.csv"

Analysis

In the first test, fake_gateway is a Mock configured with a fixed return value, acting as a stub for the Assert phase's behavioral check (result is True), and then the same object is used as a spy/mock to verify the interaction with fake_gateway.charge.assert_called_once_with(100), confirming OrderProcessor called its dependency correctly. Notice the test never touches a real payment gateway, so it runs instantly and deterministically regardless of network conditions. In the second test, patch() temporarily replaces datetime.date so that today() returns a fixed date only for the duration of the test, letting us test date-dependent logic without it actually depending on the real calendar date — a common technique for making time-based code testable. Together, these examples show how test doubles let you isolate the unit under test from anything slow, non-deterministic, or external.

🏏

Cricket analogy: A commentator first confirms the batter's stroke result (four runs, a stub check) then reviews the replay to confirm the bowler bowled exactly the planned yorker (mock verification), all without a real match ball ever needing to be bowled live.

Key Takeaways

  • The five canonical test doubles are dummy, stub, spy, mock, and fake.
  • A dummy is never used; a stub returns canned data; a spy records calls; a mock verifies expected calls; a fake is a simplified working implementation.
  • Python's unittest.mock.Mock() can act as a stub, spy, or mock depending on configuration and assertions.
  • patch() temporarily replaces a real object with a Mock for the duration of a test.
  • Test doubles isolate code from slow, unreliable, or external dependencies, keeping unit tests fast and deterministic.

Practice what you learned

Was this page helpful?

Topics covered

#Python#SoftwareEngineeringStudyNotes#SoftwareEngineering#MockingAndTestDoubles#Mocking#Test#Doubles#Explanation#Testing#StudyNotes#SkillVeris