Mocking with unittest.mock
The mock is the dependency stub: the unittest.mock.patch replaces the target (the function, the method, the module) with the MagicMock (the auto-attribute, the return_value the configured), and the test asserts the call (the assert_called_once_with, the call_count). The patch is the context manager or the decorator (the scope the test, the restore on the exit), the patch.object the instance, the patch.dict the os.environ, and the pytest-mock plugin adds the mocker fixture (the mocker.patch the no-decorator form). This chapter covers the patch (the context, the decorator, the as), the return_value/side_effect, the call assertion (assert_called, the call_args), and the pytest-mock the mocker fixture.
The patch: The Context and the Decorator
# the patch: the the REPLACE (the target
# the the MagicMock, the
# restore on the exit)
from unittest.mock import patch, MagicMock
from texttools import export_words
def test_export_calls_writer():
# the CONTEXT (the scope, the
# the restore on the with-exit):
with patch("texttools.io.write_file") as w:
w.return_value = None
export_words("a b", "out.txt")
w.assert_called_once_with("out.txt", "a b")
# the w: the the MagicMock (the
# the call RECORD, the)
# the DECORATOR (the test, the
# the):
@patch("texttools.io.write_file")
def test_export_decorator(w):
export_words("a b", "out.txt")
w.assert_called_once()
# the the w: the the MagicMock the
# the
The patch is the context manager or the decorator: the patch("texttools.io.write_file") replaces the target (the write_file the texttools.io module) with the MagicMock, and the as w (the context) or the test argument (the decorator) hands the mock - the w.return_value = None configures, the export_words calls the mock (the no real I/O), and the w.assert_called_once_with("out.txt", "a b") asserts the call (the target, the args, the once). The patch.object patches the instance attribute (the patch.object(instance, "method")), the patch.dict(os.environ, {...}) the environment, and the restore is automatic (the with-exit, the decorator's after) - the mock's scope is the test, the no global leak. The rule is the one: the patch the target in the module under test (the texttools.io.write_file, not the texttools.io the import source - the where it is looked up), and the next section's side_effect is the mock's behavior beyond the return_value.
The return_value and the side_effect
# the return_value: the the FIXED (the
# the)
from unittest.mock import patch, MagicMock
def test_fetch_value():
with patch("texttools.net.fetch") as f:
f.return_value = "the body"
assert fetch_text("url") == "the body"
# the side_effect: the the CALLABLE / the the ITERABLE
# (the per-call, the
# the)
def test_fetch_side():
with patch("texttools.net.fetch") as f:
f.side_effect = ["first", "second"]
assert fetch_text("url") == "first"
assert fetch_text("url") == "second"
# the RAISE: the side_effect the
# the EXCEPtion (the)
with patch("texttools.net.fetch") as f:
f.side_effect = ConnectionError("the down")
with pytest.raises(ConnectionError):
fetch_text("url")
# the call RECORD: the the mock's the
# the call_args (the last),
# the mock_calls (the all),
# the call_count (the int)
The return_value is the fixed (the every call returns the same, the f.return_value = "the body"), and the side_effect is the per-call: the callable (the lambda url: f"body-{url}" the computed), the iterable (the ["first", "second"] the per-call pop, the StopIteration the exhausted), or the exception (the side_effect = ConnectionError the raise). The call record is the mock's memory: the call_args (the last call's args/kwargs, the call_args[0] the tuple, the call_args[1] the dict), the mock_calls (the all, the order), and the call_count (the int) - the assertion on the behavior (the assert_called_once_with, the assert_any_call). The autospec=True is the signature-check (the patch(..., autospec=True) the wrong-arg the TypeError), and the pytest-mock (the next section) is the fixture form - the two are the mock's behavior and the mock's interface, the next section's mocker the fixture the no-decorator.
The pytest-mock: The mocker Fixture
# the pytest-mock: the the mocker FIXTURE (the
# the no-decorator, the
# the)
import pytest
def test_export_mocker(mocker):
w = mocker.patch("texttools.io.write_file")
w.return_value = None
export_words("a b", "out.txt")
w.assert_called_once_with("out.txt", "a b")
# the mocker: the MagicMock the
# the
# the
def test_env_mocker(mocker):
mocker.patch.dict("os.environ", {"CI": "1"})
assert os.environ.get("CI") == "1"
# the restore: the
# the
The pytest-mock plugin adds the mocker fixture: the mocker.patch is the no-decorator form (the w = mocker.patch("texttools.io.write_file") the mock, the no @patch, the no with), the mocker.patch.object the instance, the mocker.patch.dict the os.environ (the {"CI": "1" the set, the restore on the teardown), and the mocker.MagicMock the bare mock the test builds. The fixture scope is the function (the fresh per test, the auto-restore), and the rule is the same as the patch: the target in the module under test (the texttools.io.write_file the lookup, not the texttools.io the source). The mocker is the fixture-first (the no decorator clutter, the) and the patch the context/decorator (the explicit) - the two are the same unittest.mock, and the next chapter's monkeypatch is the lighter stub the attribute and the env the no mock object.
The Working Rules
- The
patchis the context or the decorator, the restore automatic. Thepatch("texttools.io.write_file")theMagicMock, theas wthe mock (the context) or the test argument (the decorator), the with-exit/after the restore - the scope the test, the no global leak. - The patch the target in the module under test. The
texttools.io.write_file(the lookup), not thetexttools.io(the source) - thewhere it is looked up, thepatch.objectthe instance, thepatch.dicttheos.environ. - The
return_valuethe fixed, theside_effectthe per-call. The callable the computed, the iterable the per-call pop, the exception the raise - thecall_argsthe last, themock_callsthe all, thecall_countthe int, theautospecthe signature-check. - The
pytest-mockthemockerfixture, the no-decorator. Themocker.patchthe mock, themocker.patch.dicttheos.environ(the restore), the function scope the fresh - the fixture-first themocker, the explicit thepatch.
Summary
The mock is the dependency stub: the unittest.mock.patch replaces the target (the texttools.io.write_file the lookup, not the source) with the MagicMock, and the return_value the fixed, the side_effect the per-call (the callable, the iterable, the exception). The patch is the context manager or the decorator (the as w the mock, the test argument the decorator's, the restore automatic), the patch.object the instance, the patch.dict the os.environ, and the call record is the call_args (the last), the mock_calls (the all), the call_count (the int) - the assert_called_once_with the behavior assertion, the autospec the signature-check. The pytest-mock plugin adds the mocker fixture (the mocker.patch the no-decorator, the mocker.patch.dict the os.environ the restore, the function scope) - the fixture-first the mocker, the explicit the patch. The next chapter's monkeypatch is the lighter stub: the attribute and the env the no mock object, the setattr/setenv the direct replace.