@Patch 装饰器与 pytest fixture 不兼容
我遇到了一些神秘的事情,就是在使用mock包里的patch装饰器和pytest的fixture结合时,出现了一些问题。
我有两个模块:
-----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()
看起来patch装饰器和pytest的fixture不太兼容。有没有人对此有见解?谢谢!
7 个回答
如果你有多个补丁需要应用,补丁的顺序是很重要的:
# 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
从Python3.3开始,mock
模块已经并入了unittest
库。如果你使用的是旧版本的Python,还有一个独立的mock
库可以使用。
如果在同一个测试套件中同时使用这两个库,就会出现上面提到的错误:
E fixture 'fixture_name' not found
在你的测试套件的虚拟环境中,运行pip uninstall mock
,确保你没有同时使用旧版的库和核心的unittest库。如果你在卸载后重新运行测试,可能会看到ImportError
的错误信息。
把所有的导入语句替换成from unittest.mock import <stuff>
。
希望这个对旧问题的回答能帮助到某个人。
首先,这个问题没有包含错误信息,所以我们并不真的知道发生了什么。不过我会尽量提供一些对我有帮助的内容。
如果你想要一个带有修补对象的测试,那么为了让它在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会查找测试函数或方法中的fixture名称。提供*args
参数可以很好地解决查找阶段的问题。所以,如果你想要包含一个带修补的fixture,你可以这样做:
# 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的fixture
和mock.patch
时,测试参数的顺序非常重要。
如果你把一个fixture参数放在一个被模拟的参数之前:
from unittest import mock
@mock.patch('my.module.my.class')
def test_my_code(my_fixture, mocked_class):
那么模拟对象会在my_fixture
里,而mocked_class
会被当作一个fixture来查找:
fixture 'mocked_class' not found
但是,如果你把顺序反过来,把fixture参数放在最后:
from unittest import mock
@mock.patch('my.module.my.class')
def test_my_code(mocked_class, my_fixture):
那么一切都会正常。
我也遇到过同样的问题,解决办法是使用1.0.1版本的mock库(之前我用的是2.6.0版本的unittest.mock)。现在一切都正常了,真是太好了 :)