Mocking and Patching

RoadmapsPython Backend

Scenario

Your CI pipeline is failing randomly because an external payment API (Stripe) is rate-limiting your test runner. Tests shouldn't hit real external APIs.

Mental model

Mocking is like a movie set. Instead of using a real bank vault (an external API), you build a wooden prop that looks like a vault. The actors (your code) interact with the prop, and you control exactly what the prop does.

Deep dive

In Python, `unittest.mock.patch` temporarily replaces a real object (like a function or a class) with a `MagicMock` during a test. A mock records how it was called and can be configured to return specific values.

FastAPI provides a superior alternative to `patch` for APIs: `app.dependency_overrides`. Instead of monkey-patching Python's internals, you tell the framework to inject a fake dependency when running tests.

Code examples

Bad: Patching internals

from unittest.mock import patch

@patch('app.services.payment.charge_stripe')
def test_payment(mock_charge):
    mock_charge.return_value = True
    # Brittle: if the import path changes, the mock breaks
    res = process_order() 
    mock_charge.assert_called_once()

Patching requires knowing exactly where the module is imported. It is highly brittle and can cause weird side effects if not cleaned up.

Good: FastAPI Dependency Overrides

from fastapi.testclient import TestClient
from app.main import app
from app.dependencies import get_payment_gateway

class FakeGateway:
    def charge(self, amount):
        return True

# Override the dependency
app.dependency_overrides[get_payment_gateway] = FakeGateway

client = TestClient(app)

def test_payment_endpoint():
    res = client.post('/checkout')
    assert res.status_code == 200
    # Clean up override after test
    app.dependency_overrides = {}

Instead of `patch`, we override the FastAPI dependency. This is typesafe, refactor-friendly, and respects the framework's lifecycle.

Common mistakes

Recall questions

Questions & answers

How do you test an endpoint that sends an email without actually sending an email?

If the email sender is injected via FastAPI `Depends`, I would use `app.dependency_overrides` to inject a `FakeEmailSender` that just appends the email to an in-memory list. Then I can assert the list length.

Why is FastAPI's dependency overriding superior to `unittest.mock.patch`?

`patch` relies on string paths which break during refactoring and can cause state leakage if not torn down. Dependency overrides are strongly typed, robust against refactoring, and explicitly supported by the framework.

Continue learning

Previous: Pytest Basics and Fixtures

Return to Python Backend Roadmap