我正在编写一个带有灯具的pytest插件,该灯具具有设置一些理想模拟的副作用。我想编写一个简单的标记,允许用户在测试运行之前调用此夹具设置,而不必将夹具包含在测试功能参数中 - 基本上,"注入"使用标记的夹具。我的理由是用户可能想要模拟设置而不需要夹具本身的返回值,在这种情况下,使用标记对我来说似乎更直观,而不是要求他们声明他们赢得使用的夹具不能使用
我如何使用标记来要求pytest中的夹具?查看文档,似乎我想要挂钩pytest_collection_modifyitems
之类的东西,使用Item.iter_markers
检查每个项目上的相关标记,然后以某种方式更新灯具列表。但是,阅读代码时,我无法确定如何准确触发该夹具设置。
以下是有关灯具的简化示例:
@pytest.fixture
def mocks(mocker):
ret_val = 10
mocker.patch('path.to.patch', return_value=ret_val)
return ret_val
以下是用户现在可以设置模拟的内容:
def test_mocks(mocks):
# 'path.to.patch' will be mocked in this test
# ... test code ...
但是,如果可以通过标记触发灯具,那么测试可能会是什么样子:
@pytest.mark.mocks
def test_mocks():
# 'path.to.patch' will be mocked in this test, too
# ... test code ...
答案 0 :(得分:3)
使用usefixtures
标记:
# conftest.py
import pytest
@pytest.fixture
def mocks(mocker):
mocker.patch('os.path.isdir', return_value=True)
# test_me.py
import os
import pytest
@pytest.mark.usefixtures('mocks')
def test_mocks():
assert os.path.isdir('/this/is/definitely/not/a/dir')
传递多个灯具也是可行的:
@pytest.mark.usefixtures('mocks', 'my_other_fixture', 'etc')
但是,有一点需要注意:代码中的mocks
fixture返回值ret_val
。通过测试函数args传递夹具时,此值将在mocks
arg下返回;当你使用标记时,你不再拥有arg,所以你不能使用这个值。如果您需要模拟值,请在测试函数args中传递fixture。还有其他一些可以想象的方法,比如通过缓存传递ret_val
,然而,生成的代码会更复杂,更不易读,所以我不会打扰。
答案 1 :(得分:1)
我能够通过使用pytest_collection_modifyitems
hook在收集后调整测试项目上的灯具列表来实现这一点:
@pytest.hookimpl(trylast=True)
def pytest_collection_modifyitems(items):
'''
Check if any tests are marked to use the mock.
'''
for item in items:
# Note that `get_marker` has been superceded by `get_closest_marker`
# in the development version of pytest
if item.get_marker('mocks'):
item.fixturenames.append('mocks')
收集后调整Item.fixturenames
列表会以我希望的方式触发灯具设置。
如果您不关心使用自定义标记,@ hoefling建议使用内置usefixtures
标记也是一个很好的解决方案。