0
0
PytestComparisonBeginner · 3 min read

Monkeypatch vs Mock in pytest: Key Differences and Usage

In pytest, monkeypatch directly replaces attributes or functions at runtime, while mock creates mock objects to simulate and control behavior. monkeypatch is simpler for quick replacements, and mock offers more control and inspection of calls.
⚖️

Quick Comparison

This table summarizes the main differences between monkeypatch and mock in pytest.

Factormonkeypatchmock
PurposeReplace attributes or functions at runtimeCreate mock objects to simulate behavior
ControlSimple direct replacementDetailed control over calls and return values
InspectionNo built-in call trackingTracks calls, arguments, and call count
SetupUses pytest fixture monkeypatchUse unittest.mock or pytest-mock plugin
Use caseQuick patching of simple functions or variablesComplex mocking with assertions on usage
CleanupAutomatic after test endsAutomatic with context managers or decorators
⚖️

Key Differences

monkeypatch is a pytest fixture that lets you replace or delete attributes, dictionary items, or environment variables temporarily during a test. It works by directly changing the target object at runtime, which makes it very straightforward for simple patches like swapping a function or changing a global variable.

On the other hand, mock (from Python's unittest.mock module) creates mock objects that simulate real objects. These mocks can record how they were used, what arguments were passed, and how many times they were called. This makes mock powerful for verifying interactions and controlling complex behavior.

While monkeypatch is great for quick and simple replacements, mock is better when you need detailed control and assertions on how the mocked parts are used. Both clean up automatically after tests, but mock often requires explicit setup via decorators or context managers, whereas monkeypatch is provided as a fixture by pytest.

⚖️

Code Comparison

python
def get_data():
    return 'real data'

def process():
    return get_data().upper()

def test_process_with_monkeypatch(monkeypatch):
    def fake_get_data():
        return 'fake data'
    monkeypatch.setattr(__name__, 'get_data', fake_get_data)
    result = process()
    assert result == 'FAKE DATA'
↔️

Mock Equivalent

python
from unittest import mock

def get_data():
    return 'real data'

def process():
    return get_data().upper()

def test_process_with_mock():
    with mock.patch(__name__ + '.get_data', return_value='fake data') as mocked_get:
        result = process()
        mocked_get.assert_called_once()
        assert result == 'FAKE DATA'
🎯

When to Use Which

Choose monkeypatch when you want a quick and simple way to replace functions, variables, or environment settings without needing to track calls or assert usage details. It's perfect for straightforward patches in pytest tests.

Choose mock when you need detailed control over the mocked object's behavior, want to assert how many times it was called, with what arguments, or simulate complex interactions. It's ideal for verifying interactions and behavior in more complex test scenarios.

Key Takeaways

monkeypatch replaces attributes simply and is built into pytest as a fixture.
mock creates mock objects with detailed call tracking and control.
Use monkeypatch for quick, simple patches and mock for complex behavior verification.
Both clean up automatically after tests to avoid side effects.
Choosing depends on whether you need call inspection (mock) or just replacement (monkeypatch).