Mocking Dependencies with unittest.mock
pytest does not ship its own mocking library, but it works extremely well with unittest.mock, which is part of the Python standard library. This allows you to replace external dependencies, network calls, or expensive operations with controlled mock objects. Mock objects are sometimes called test doubles, spies, fakes or stubs. By combining pytest’s monkeypatch fixture with the unittest.mock module, you can cover nearly all common test double use cases.
A common pattern when using unittest.mock is to rely on patch, either as a decorator or as a context manager:
from unittest.mock import patch
def fetch_data():
return "real data"
def test_fetch_data():
with patch(__name__ + ".fetch_data", return_value="mocked data"):
assert fetch_data() == "mocked data"In this example, patch temporarily replaces the fetch_data function in the current module with a mock object for the duration of the with block. Any call to fetch_data() inside this block does not execute the original function. Instead, it returns the value specified by return_value. Once the block exits, the original function is automatically restored. This scoping behavior ensures that mocks do not leak into other tests.
In addition to patch, unittest.mock provides the MagicMock class, which is a flexible mock object that can dynamically handle attribute access, method calls, and return values without requiring explicit definitions.
from unittest.mock import MagicMock
def process(service):
return service.run()
def test_process_with_magicmock():
service = MagicMock()
service.run.return_value = "mocked result"
result = process(service)
assert result == "mocked result"
service.run.assert_called_once() # verifies that run() was invoked exactly onceHere, MagicMock is used to stand in for a dependency object. The run method does not exist on a real class, but MagicMock allows it to be accessed and configured anyway. The assertion service.run.assert_called_once() verifies that this method was invoked exactly once, ensuring that the function under test interacts with its dependency as expected.
While unittest.mock works well with pytest, many teams prefer using the pytest-mock plugin, which provides a thin and convenient wrapper around unittest.mock. The plugin introduces a built-in mocker fixture that simplifies mock creation and automatically handles cleanup between tests.
Using pytest-mock, the earlier patch example can be rewritten in a more pytest-native style:
def fetch_data():
return "real data"
def test_fetch_data(mocker):
mocker.patch(__name__ + ".fetch_data", return_value="mocked data")
assert fetch_data() == "mocked data"Similarly, MagicMock can be used as mocker.MagicMock, without changing rest of the code in the example.
