Skip to main content

Mocking with unittest.mock

Mocking replaces a real dependency (a database call, an HTTP request, a file read) with a controlled fake. Your unit test then runs in isolation — fast, deterministic, no network required.

The Problem Without Mocking

def get_user_name(user_id: int) -> str:
    row = database.query(f"SELECT name FROM users WHERE id={user_id}")
    return row["name"]

def test_get_user_name():
    #  requires a running database with test data
    assert get_user_name(1) == "Alice"

unittest.mock.patch

from unittest.mock import patch, MagicMock

def test_get_user_name():
    with patch("myapp.database.query") as mock_query:
        mock_query.return_value = {"name": "Alice"}
        result = get_user_name(1)

    assert result == "Alice"
    mock_query.assert_called_once_with("SELECT name FROM users WHERE id=1")

patch replaces the target for the duration of the with block and restores the original afterwards.

pytest-mock (Cleaner Syntax)

pip install pytest-mock
def test_get_user_name(mocker):
    mock_query = mocker.patch("myapp.database.query")
    mock_query.return_value = {"name": "Alice"}

    assert get_user_name(1) == "Alice"
    mock_query.assert_called_once()

The mocker fixture handles cleanup automatically — no with block needed.

Common Mock Assertions

mock.assert_called()                         # called at least once
mock.assert_called_once()                    # called exactly once
mock.assert_called_with(arg1, key=val)       # called with specific args
mock.assert_not_called()                     # never called

# Inspect call history
print(mock.call_count)                       # number of calls
print(mock.call_args)                        # args of last call
print(mock.call_args_list)                   # args of all calls

Mocking HTTP Requests

import requests

def fetch_quote():
    resp = requests.get("https://api.quotable.io/random")
    return resp.json()["content"]

def test_fetch_quote(mocker):
    mock_get = mocker.patch("requests.get")
    mock_get.return_value.json.return_value = {"content": "Test quote"}

    result = fetch_quote()
    assert result == "Test quote"
    mock_get.assert_called_once_with("https://api.quotable.io/random")

Mock vs Real Dependency

Mock isolation visualiser
Ctrl+Enter
HTML
CSS
JS
Preview

MagicMock for Complex Objects

mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {"token": "abc123"}

# Supports context manager protocol
with patch("requests.post", return_value=mock_response) as mock_post:
    token = login("alice", "pass")
    assert token == "abc123"

MagicMock supports magic methods (__enter__, __exit__, __len__, etc.) automatically.