在同一模块中使用unittest.mock的补丁,通过“__main__.imported_obj”修补时得到“没有该属性”

Int*_*rer 6 python unit-testing mocking pytest python-unittest.mock

我的任务本来应该很简单,但它却困扰了我一段时间。我正在尝试将patch一个对象导入到当前模块中。

根据Python 中模拟修补 from/import 语句的答案

我应该就可以了patch("__main__.imported_obj")。但是,这对我不起作用。请参阅我下面的最小重现(我正在通过以下方式运行测试pytest):

最小重现

这是使用 Python 3.8.6 运行的。

from random import random
from unittest.mock import patch

import pytest

@pytest.fixture
def foo():
    with patch("__main__.random"):
        return

def test(foo) -> None:
    pass
Run Code Online (Sandbox Code Playgroud)

当我使用 PyCharm 运行此代码时,我得到一个AttributeError

AttributeError: <module '__main__' from '/Applications/PyCharm.app/Contents/plugins/python/helpers/pycharm/_jb_pytest_runner.py'> does not have the attribute 'random'
Run Code Online (Sandbox Code Playgroud)

此外,当我在 之前的行中进入调试器模式时with patch,我看到该属性__main__未定义。我不确定是否需要定义它patch发挥其魔力。

注意:我知道我可以使用patch.object并且它变得更加容易。但是,我正在尝试弄清楚如何patch在这个问题中使用。

研究

即使使用文档中的示例,也无法模拟打开

这个问题是相关的,因为它是类似的错误消息和用例。他们的解决方案是使用builtins代替__main__,但那是因为他们尝试使用patch内置函数(open)。

MrB*_*men 6

您假设运行测试的模块是__main__,但只有通过 调用它时才会出现这种情况main。如果您使用的是,通常会出现这种情况unittest。使用 pytest,测试位于定义它们的模块中。

您必须修补当前模块,其名称可通过 访问__name__,而不是假设特定的模块名称:

from random import random
from unittest.mock import patch

import pytest

@pytest.fixture
def foo():
    with patch(__name__ + ".random"):
        yield
Run Code Online (Sandbox Code Playgroud)