I am following this mini-tutorial/blog on pytest-mock. I can not understand how the mocker
is working since there is no import for it - in particular the function declaration def test_mocking_constant_a(mocker):
import mock_examples.functions
from mock_examples.functions import double
def test_mocking_constant_a(mocker):
mocker.patch.object(mock_examples.functions, 'CONSTANT_A', 2)
expected = 4
actual = double() # now it returns 4, not 2
assert expected == actual
Somehow the mocker
has the attributes/functions of pytest-mocker.mocker
: in particular mocker.patch.object
. But how can that be without the import statement?
The mocker
variable is a Pytest fixture. Rather than using imports, fixtures are supplied using dependency injection - that is, Pytest takes care of creating the mocker object for you and supplies it to the test function when it runs the test.
Pytest-mock defines the "mocker" fixture here, using the Pytest fixture
decorator. Here, the fixture
decorator is used as a regular function, which is a slightly unusual way of doing it. A more typical way of using the fixture
decorator would look something like this:
@pytest.fixture()
def mocker(pytestconfig: Any) -> Generator[MockerFixture, None, None]:
"""
Return an object that has the same interface to the `mock` module, but
takes care of automatically undoing all patches after each test method.
"""
result = MockerFixture(pytestconfig)
yield result
result.stopall()
The fixture
decorator registers the "mocker" function with Pytest, and when Pytest runs a test with a parameter called "mocker", it inserts the result of the "mocker" function for you.
Pytest can do this because it uses Python's introspection features to view the list of arguments, complete with names, before calling the test function. It compares the names of the arguments with names of fixtures that have been registered, and if the names match, it supplies the corresponding object to that parameter of the test function.