pytest 模拟程序如何在没有导入语句的情况下工作?

How does a pytest mocker work given there is no import statement for it?

我正在关注 this mini-tutorial/blog on pytest-mock。我无法理解 mocker 是如何工作的,因为它没有导入 - 特别是函数声明 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

不知何故 mocker 具有 pytest-mocker.mocker 的 attributes/functions:特别是 mocker.patch.object。但是没有导入语句怎么可能呢?

mocker 变量是 Pytest fixture。 fixture 不是使用导入,而是使用依赖注入提供 - 也就是说,Pytest 负责为您创建模拟对象,并在运行测试时将其提供给测试函数。

Pytest-mock 定义了“模仿者”夹具 here, using the Pytest fixture 装饰器。在这里, fixture 装饰器被用作常规函数,这是一种稍微不寻常的做法。使用 fixture 装饰器的更典型的方式是这样的:

@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()

fixture 装饰器向 Pytest 注册了“mocker”函数,当 Pytest 使用名为“mocker”的参数运行测试时,它会为您插入“mocker”函数的结果。

Pytest 可以做到这一点,因为它使用 Python 的内省功能在调用测试函数之前查看参数列表,包括名称。它将参数的名称与已注册的固定装置的名称进行比较,如果名称匹配,它将相应的对象提供给测试函数的该参数。