Monkey Patching
The monkeypatch fixture is the lighter stub than the mock: the setattr replaces the attribute (the module global, the class method), the setenv/delenv the os.environ, the setitem/delitem the dict, and the auto-undo (the every change reverted on the teardown, the no patch context). The monkeypatch is the mock's sibling for the simple replace (the no call record, the no return_value - the value is the set, not the configured). This chapter covers the setattr (the module global, the class method, the raising), the setenv/delenv (the os.environ), the setitem/delitem (the dict), and the auto-undo (the teardown's revert, the monkeypatch.undo).
The setattr: The Attribute Replace
# the setattr: the the REPLACE (the value,
# the)
import pytest
import texttools.config
def test_config_value(monkeypatch):
# the module GLOBAL (the
# the):
monkeypatch.setattr(texttools.config, "MAX_LEN", 10)
assert texttools.config.MAX_LEN == 10
# the
# the
def test_method(monkeypatch):
# the CLASS METHOD (the
# the):
monkeypatch.setattr("texttools.io.write_file",
lambda path, content: None)
export_words("a b", "out.txt")
# the
The setattr is the attribute replace: the monkeypatch.setattr(texttools.config, "MAX_LEN", 10) the module global (the object plus the name, the value), the monkeypatch.setattr("texttools.io.write_file", func) the string form (the target.attr the dotted, the raising the AttributeError when the attribute is absent), and the monkeypatch.setattr(obj, "method", func) the class method (the instance the no patch, the class the all instance). The monkeypatch is the fixture (the function scope, the no import of the mock, the no patch context) - the simple replace (the value the set, the no call record, the no return_value), and the auto-undo (the next section) is the teardown's revert. The rule is the one: the monkeypatch is the simple replace (the config, the flag, the small function), the mock is the behavior (the call record, the side_effect, the autospec) - the two are the stub's two weights, and the next section's setenv is the environment half.
The setenv and the setitem
# the setenv/delenv: the the os.environ (the
# the)
import os
import pytest
def test_env(monkeypatch):
monkeypatch.setenv("TEXTTOOLS_LANG", "en")
assert os.environ["TEXTTOOLS_LANG"] == "en"
# the
# the
def test_delenv(monkeypatch):
monkeypatch.delenv("TEXTTOOLS_DEBUG", raising=False)
assert "TEXTTOOLS_DEBUG" not in os.environ
# the raising=False: the
# the
def test_setitem(monkeypatch):
# the setitem/delitem: the the DICT (the
# the)
d = {"a": 1}
monkeypatch.setitem(d, "b", 2)
assert d == {"a": 1, "b": 2}
monkeypatch.delitem(d, "a")
assert d == {"b": 2}
The setenv/delenv is the os.environ (the setenv("TEXTTOOLS_LANG", "en") the set, the delenv the remove, the raising=False the no-KeyError on the absent) - the environment the test controls (the CI flag, the LANG), and the setitem/delitem is the dict (the setitem(d, "b", 2) the set, the delitem(d, "a") the remove, the raising the KeyError the absent). The monkeypatch is the one fixture for the three targets (the attribute, the env, the dict), and the auto-undo is the teardown's revert - the next section. The rule is the one: the monkeypatch is the simple replace (the no call record, the value the set), the mock is the behavior (the return_value, the side_effect) - the two are the stub's two weights, and the monkeypatch the lighter (the no import, the no MagicMock), the mock the heavier (the). The next section's auto-undo is the monkeypatch's guarantee.
The Auto-Undo
# the AUTO-UNDO: the the every change the REVERT on
# the
# the
import pytest
def test_undo(monkeypatch):
import texttools.config
old = texttools.config.MAX_LEN
monkeypatch.setattr(texttools.config, "MAX_LEN", 99)
assert texttools.config.MAX_LEN == 99
# the test ENDS: the REVERT
# the
def test_next_sees_old():
import texttools.config
# the
# the
assert texttools.config.MAX_LEN != 99
# the
The auto-undo is the monkeypatch's guarantee: the every change (the setattr, the setenv, the setitem) is reverted on the teardown (the monkeypatch fixture's finalizer, the monkeypatch.undo the manual), so the next test sees the original (the test_next_sees_old the MAX_LEN not the 99, the no cross-test leak). The monkeypatch is the function scope (the fresh per test, the undo on the per-test teardown), and the monkeypatch.context() (the context manager) is the no-fixture form (the with monkeypatch.context() as m: the manual scope, the m.undo() the explicit). The rule is the one: the monkeypatch is the change-plus-undo (the no manual restore, the no try/finally), the patch is the replace-plus-restore (the mock's), and the monkeypatch the lighter (the no mock object, the value the set) - the next chapter's async testing is the async def test the pytest-asyncio runs.
The Working Rules
- The
setattris the attribute replace, theraisingtheAttributeError. Thesetattr(obj, "attr", value)the object-plus-name, thesetattr("a.b.attr", value)the dotted, theraising=Falsethe no-error on the absent - the module global, the class method, the instance the no. - The
setenv/delenvtheos.environ, thesetitem/delitemthe dict. Thesetenvthe set, thedelenvthe remove (theraising=Falsethe absent), thesetitemthe dict's set, thedelitemthe remove - the one fixture the three targets. - The auto-undo is the teardown's revert, the
monkeypatch.undothe manual. The every change reverted (thesetattr, thesetenv, thesetitem), the next test sees the original (the no cross-test leak), themonkeypatch.context()the no-fixture form. - The
monkeypatchthe simple replace, themockthe behavior. Themonkeypatchthe value the set (the no call record, the noreturn_value), themocktheside_effectplus theassert_called- the two weights, themonkeypatchthe lighter.
Summary
The monkeypatch fixture is the lighter stub than the mock: the setattr replaces the attribute (the module global, the class method, the raising the AttributeError), the setenv/delenv the os.environ (the raising=False the absent), the setitem/delitem the dict, and the auto-undo reverts the every change on the teardown (the monkeypatch.undo the manual, the monkeypatch.context() the no-fixture). The monkeypatch is the function scope (the fresh per test, the undo on the per-test teardown, the no cross-test leak), and the rule is the split: the monkeypatch is the simple replace (the value the set, the no call record), the mock is the behavior (the return_value, the side_effect, the assert_called) - the two weights, the monkeypatch the lighter (the no import, the no MagicMock). The next chapter's async def test is the pytest-asyncio the plugin runs, the @pytest.mark.asyncio the mark, and the event loop the fixture the plugin manages.