pyguides

unittest.mock module: mocking and patching in Python tests

Overview

The unittest.mock module provides tools for replacing real objects in your tests with mock objects that you control. The unittest.mock module is part of the Python standard library since version 3.3. Mock a database, an HTTP client, or a filesystem call — you decide what the mock returns, and you can then assert that it was called with the arguments you expect.

Mocking is essential for testing code that depends on external services. You want fast, isolated tests that verify your code’s behavior without anything actually hitting the network or the disk.

unittest.mock is part of the standard library in Python 3.3+. A backport for older Python versions is available on PyPI as mock.

Mock Objects

The Mock class

Mock creates objects that record how they were used. Any attribute or method you access is created automatically and stored for later inspection:

from unittest.mock import Mock

mock = Mock()
mock.method(1, 2, key='value')
mock.attribute

mock.method.called          # => True
mock.method.call_count     # => 1
mock.method.call_args       # => call(1, 2, key='value')
mock.attribute              # => returns a new Mock

A bare Mock records every interaction automatically, but the values it returns are themselves new Mock instances. That is rarely useful on its own. To make the mock produce meaningful data, you configure its return_value attribute before calling it. This is how you simulate a real function or method response:

Configuring return values

Set return_value to control what the mock returns when called:

api = Mock()
api.fetch_user.return_value = {'id': 1, 'name': 'Alice'}

result = api.fetch_user(42)
result  # => {'id': 1, 'name': 'Alice'}

Setting return_value gives the mock predictable output, but the mock still accepts any attribute access without complaint. A typo like api.fetch_userr(42) would silently create a new Mock instead of failing. To catch these mistakes, you can restrict the mock to the shape of a real class:

Specifying an interface with spec

Use spec to restrict the mock to the interface of a real class. Accessing undefined attributes raises AttributeError:

from unittest.mock import Mock
from collections import OrderedDict

mock = Mock(spec=OrderedDict)
mock.missing_method()
# => AttributeError: OrderedDict has no attribute 'missing_method'

Using spec makes your mock faithful to the real interface, catching attribute errors early. Standard Mock objects do not implement Python’s protocol methods like str or len however, so calling str() or len() on a plain Mock returns a generic representation. When you need these magic methods to behave like the real object, switch to MagicMock:

MagicMock

MagicMock is a Mock subclass that pre-creates all magic methods. Use it when you need to mock objects that implement __str__, __len__, __iter__, or other dunder methods:

from unittest.mock import MagicMock

mock = MagicMock()
mock.__str__.return_value = 'custom string'

str(mock)  # => 'custom string'
mock['key']  # => returns a MagicMock

If you do not need magic methods, Mock is sufficient. So far we have been creating mocks directly and passing them around by hand, which works for simple cases but becomes unwieldy when the code under test imports its dependencies from other modules. The patch() function solves this by temporarily swapping a name in another module with a mock for the duration of a single test:

patch()

patch() replaces an attribute in a module or class for the duration of a test. It is the most common entry point for mocking in unit tests.

As a decorator

from unittest.mock import patch
import mymodule

@patch('mymodule.Database')
def test_save(MockDatabase):
    MockDatabase.return_value.query.return_value = [{'id': 1}]

    result = mymodule.get_data()

    MockDatabase.assert_called_once()
    assert result == [{'id': 1}]

The mock is passed as an argument to the decorated function. With nested decorators, mocks are passed bottom-up. The decorator form keeps your test function signature clean but commits you to patching for the entire test body. If you only need the mock for part of a test, a context manager gives you finer control over the mock’s lifetime:

As a context manager

def test_save():
    with patch('mymodule.Database') as MockDatabase:
        MockDatabase.return_value.query.return_value = [{'id': 1}]
        result = mymodule.get_data()

    assert result == [{'id': 1}]

Both the decorator and context manager forms of patch() target a name in a module namespace. When you need to replace a specific attribute on an object instance rather than a module-level name, patch.object provides a more direct syntax:

patch.object

patch.object patches a specific attribute on an object rather than in a module:

def test_timeout():
    obj = SomeClass()

    with patch.object(obj, 'timeout', 99):
        assert obj.timeout == 99

patch.object is handy for overriding instance attributes during a test. Dictionary-based configuration and environment variables are another common patching target. Instead of manually saving and restoring dict entries, use patch.dict for a clean temporary override:

patch.dict

patch.dict temporarily sets values in a dictionary:

from unittest.mock import patch

config = {'host': 'localhost', 'port': 5432}

with patch.dict(config, {'port': 9000}):
    assert config['port'] == 9000

assert config['port'] == 5432  # restored

This is useful for mocking os.environ. All the examples so far have used return_value to supply canned responses, but sometimes you need the mock to do something more dynamic: raise an exception, cycle through a sequence of values, or run arbitrary logic. The side_effect parameter handles all of these cases:

Side Effects

side_effect runs custom code when a mock is called, instead of returning a fixed value. It can be a function, an iterable, or an exception.

Raising exceptions

mock = Mock(side_effect=ValueError('something went wrong'))
mock()  # raises ValueError

Setting side_effect to an exception class or instance makes the mock reliable for testing error-handling paths without needing to orchestrate real failures. For tests that need the mock to return different values on successive calls, pass an iterable instead:

Returning different values per call

Pass a list to return a different value on each call:

mock = Mock(side_effect=[1, 2, 3])

mock()  # => 1
mock()  # => 2
mock()  # => 3

An iterable side_effect cycles through its values one call at a time, which works well when you know the exact sequence of return values ahead of time. For conditional logic based on the mock’s input arguments, pass a callable instead:

Using a function as side effect

def fetch_remote(url):
    if 'fail' in url:
        raise ConnectionError('network error')
    return {'status': 'ok'}

mock = Mock(side_effect=fetch_remote)

mock('http://example.com')        # => {'status': 'ok'}
mock('http://fail.example.com')    # raises ConnectionError

A callable side_effect gives you full control: inspect the arguments, branch on conditions, and return or raise as needed. Once you have configured your mock and run the code under test, the next step is verifying the interactions actually happened. Mock objects record every call automatically, and the assertion API lets you express expectations about what was called and how:

Assertions

Mock objects record every call automatically:

mock = Mock()
mock.process(1, 2, key='value')

mock.assert_called_once()                    # fails if called more than once
mock.assert_called_with(1, 2, key='value') # fails if args differ
mock.assert_not_called()                    # fails if called at all

The assertion methods confirm whether a mock was called at all and with which arguments, but they do not tell you how many times each method was invoked or give you the full sequence of calls. For more detailed introspection, the mock object stores its complete call history in attributes you can query directly:

Inspect call history:

mock.method.call_count       # => 3
mock.method.call_args_list   # => [call(1), call(2), call(3)]

These assertions catch mismatches in arguments and call counts, but they do not check that the calls match the real function’s signature. A mock of a function that expects exactly two positional arguments will happily accept a call with three. To enforce signature checking at the mock level, use create_autospec:

create_autospec

create_autospec creates a mock that mirrors the call signature of the real function or class. Calling it with wrong arguments fails with the same TypeError as the real function:

from unittest.mock import create_autospec
from mymodule import some_function

mock_func = create_autospec(some_function, return_value='mocked')

mock_func(1, 2)
mock_func.assert_called_once_with(1, 2)
mock_func(1)  # => TypeError: missing a required argument

Use autospec=True on patch() for the same effect as a decorator. Signature checking catches argument mismatches that a plain Mock would silently accept, saving you from tests that pass for the wrong reasons. With the core API covered, here are three real-world patterns that combine mocks, patches, and assertions to isolate common external dependencies:

Common use cases

Mocking a database connection

@patch('mymodule.get_connection')
def test_query(MockConn):
    mock_conn = Mock()
    mock_conn.execute.return_value = [{'id': 1}]
    MockConn.return_value = mock_conn

    result = mymodule.run_query('SELECT * FROM users')

    MockConn.assert_called_once_with()
    mock_conn.execute.assert_called_once_with('SELECT * FROM users')

Database mocking uses a chain of mocks: the patched connection factory returns a mock connection, whose execute method returns a mock result set. Each layer in the chain needs its own return_value configuration. Mocking time follows a simpler pattern, replacing time.sleep with a no-op so your test runs instantly:

Mocking time

from unittest.mock import patch

with patch('time.sleep') as mock_sleep:
    my_function_that_delays()
    mock_sleep.assert_called_once_with(1)

Patching time.sleep lets you skip actual delays and still verify the function waited for the expected duration. Environment variables are another external dependency that makes tests order-dependent unless you mock them. Use patch.dict for a clean setup and teardown:

Mocking environment variables

from unittest.mock import patch

with patch.dict('os.environ', {'API_KEY': 'test-secret'}):
    result = load_config()  # reads os.environ['API_KEY']
    assert result.api_key == 'test-secret'

patch.dict restores the original dictionary contents when the context manager exits, so tests stay isolated. These patterns cover the most frequent mocking scenarios, but there are a few sharp edges worth knowing about before you write your own mocks:

Gotchas

Patching at the wrong location. You must patch where the object is looked up, not where it is defined:

# WRONG — patches the local name inside mymodule
@patch('mymodule.SomeClass')

# CORRECT — patches where SomeClass is used
@patch('production_code.SomeClass')

Patching the wrong location is the single most common mistake with unittest.mock. The rule is simple: you must patch the name in the module where it is looked up at runtime, not where the class or function is defined. Import statements create local names in the importing module, so that is where the patch must target.

Mock is too permissive by default. A Mock accepts any attribute access silently. Use spec to restrict it to the real interface:

# Without spec — silent failure
mock = Mock()
mock.nonexistent_method()  # creates a new Mock, no error

# With spec — catches mistakes
mock = Mock(spec=RealClass)
mock.nonexistent_method()  # => AttributeError

Without spec, calling a method that does not exist on the real class silently creates a new Mock that does nothing, turning what should be a failing test into a false positive. With spec, the mock enforces the real class’s attribute set and surfaces typos immediately.

Forgetting cleanup. Using patch as a decorator or context manager handles cleanup automatically. Using Mock directly for monkey-patching requires manual teardown.

See Also