@Patch 装饰器与 pytest 夹具不兼容
Posted
技术标签:
【中文标题】@Patch 装饰器与 pytest 夹具不兼容【英文标题】:@Patch decorator is not compatible with pytest fixture 【发布时间】:2014-09-23 07:24:21 【问题描述】:我在使用与 pytest 夹具集成的模拟包中的补丁装饰器时遇到了一些神秘的事情。
我有两个模块:
-----test folder
-------func.py
-------test_test.py
在func.py中:
def a():
return 1
def b():
return a()
在 test_test.py 中:
import pytest
from func import a,b
from mock import patch,Mock
@pytest.fixture(scope="module")
def brands():
return 1
mock_b=Mock()
@patch('test_test.b',mock_b)
def test_compute_scores(brands):
a()
补丁装饰似乎与 pytest 夹具不兼容。有人对此有见解吗?谢谢
【问题讨论】:
我遇到了类似的问题,我正在导入from unittest.mock import patch
和 import mock
,我不得不删除 import mock 语句,然后停止抛出 fixture 'mocked_instance' not found
错误
我建议你切换接受的答案。
【参考方案1】:
当使用 pytest fixture
和 mock.patch
时,测试参数顺序至关重要。
如果您在模拟的之前放置一个夹具参数:
from unittest import mock
@mock.patch('my.module.my.class')
def test_my_code(my_fixture, mocked_class):
然后模拟对象将在my_fixture
中,mocked_class
将作为夹具进行搜索:
fixture 'mocked_class' not found
但是,如果你颠倒顺序,把fixture参数放在最后:
from unittest import mock
@mock.patch('my.module.my.class')
def test_my_code(mocked_class, my_fixture):
那么一切都会好起来的。
【讨论】:
这是解决方案,而不是 Konrad 的解决方案。 这应该是解决方案【参考方案2】:截至 Python3.3,mock
模块已被拉入 unittest
库。还有一个反向移植(用于以前版本的 Python)作为独立库 mock
。
在同一个测试套件中组合这两个库会产生上述错误:
E fixture 'fixture_name' not found
在您的测试套件的虚拟环境中,运行pip uninstall mock
,并确保您没有在核心单元测试库旁边使用反向移植库。卸载后重新运行测试时,如果出现这种情况,您会看到 ImportError
s。
将此导入的所有实例替换为from unittest.mock import <stuff>
。
【讨论】:
【参考方案3】:这并不能直接解决您的问题,但有一个 pytest-mock 插件可以让您改写:
def test_compute_scores(brands, mock):
mock_b = mock.patch('test_test.b')
a()
【讨论】:
【参考方案4】:希望这个老问题的答案对某人有所帮助。
首先,问题不包括错误,所以我们真的不知道发生了什么。但我会尽力提供一些对我有帮助的东西。
如果你想要一个用修补对象装饰的测试,那么为了让它与 pytest 一起工作,你可以这样做:
@mock.patch('mocked.module')
def test_me(*args):
mocked_module = args[0]
或者对于多个补丁:
@mock.patch('mocked.module1')
@mock.patch('mocked.module')
def test_me(*args):
mocked_module1, mocked_module2 = args
pytest 正在寻找要在测试函数/方法中查找的夹具名称。提供*args
参数为我们提供了一个很好的解决查找阶段的方法。因此,要包含带有补丁的夹具,您可以这样做:
# from question
@pytest.fixture(scope="module")
def brands():
return 1
@mock.patch('mocked.module1')
def test_me(brands, *args):
mocked_module1 = args[0]
这对我运行 python 3.6 和 pytest 3.0.6 很有用。
【讨论】:
不幸的是,这个问题是关于在方法签名中混合 pytest 固定装置和补丁,而不仅仅是补丁。 我添加了一些关于完成问题答案的固定装置。我会说它有点老套,但它确实有效。感谢@zalpha314 指出这一点。【参考方案5】:如果您要应用多个补丁,则注入它们的顺序很重要:
# from question
@pytest.fixture(scope="module")
def brands():
return 1
# notice the order
@patch('my.module.my.class1')
@patch('my.module.my.class2')
def test_list_instance_elb_tg(mocked_class2, mocked_class1, brands):
pass
【讨论】:
【参考方案6】:我遇到了同样的问题,我的解决方案是在 1.0.1 版本中使用模拟库(在我使用 2.6.0 版本中的 unittest.mock 之前)。现在它就像一个魅力:)
【讨论】:
感谢您的回答。我在使用模拟库 1.0.1 时遇到了这个问题以上是关于@Patch 装饰器与 pytest 夹具不兼容的主要内容,如果未能解决你的问题,请参考以下文章