我想对多个灯具值运行相同的测试集,但是我不想在灯具定义中“硬编码”这些值。
我的用例是具有多个实现的接口,并且我想在每个实现上运行相同的测试。
例如,my_code.py
class Interface:
def method():
pass
class Impl1(Interface):
def method():
return 1
class Impl2(Interface):
def method():
return 2
test_interface.py:
def test_method(instance: Interface):
assert type(instance.method()) == int
test_impl1.py
from my_code import Impl1
@pytest.fixture
def instance():
return Impl1()
test_impl2.py
from my_code import Impl2
@pytest.fixture
def instance():
return Impl2()
显然,此代码不起作用(因为未找到夹具“实例”)。我可以在conftest.py
中写这样的东西@pytest.fixture(params=[Impl1(), Impl2()])
def instance(request):
return requst.param
但是我希望能够运行test_impl1.py仅测试Impl1。另外,如果我要编写Impl3,我不想更改conftest.py,我只想添加简单的test_impl3.py 如果我的实现完全在其他程序包中怎么办?
简而言之,我想针对固定装置列表中的每个值重用我的测试,但是我想在运行时更改此固定装置列表(例如,取决于可用的实现)
答案 0 :(得分:0)
最后解决了这个问题,但是不确定这是否是可靠的解决方案。
在test/common/test_common.py
中,我进行了测试:
def test_method(instance: Interface):
assert type(instance.method()) == int
在tests/common/conftest.py
中,我有一些有趣的东西:
THIS_PACKAGE = 'tests/common/'
def create_instance_hooks(meta_fixture, name):
tests_node_id = os.path.join(THIS_PACKAGE, '{}.py'.format(name))
def pytest_runtest_protocol(item, nextitem):
split = item.nodeid.split('::')
filename, *test_name = split
if filename == tests_node_id and 'instance' in item.fixturenames:
func_name = meta_fixture.__name__
meta = tuple(item.session._fixturemanager._arg2fixturedefs[func_name])
item._request._arg2fixturedefs['instance'] = meta
@pytest.hookimpl(hookwrapper=True)
def pytest_collect_file(path, parent):
outcome = yield
result = outcome.get_result()
if parent.parent is None:
result.append(
DoctestModule(os.path.join(parent.fspath, THIS_PACKAGE, 'conftest.py'), parent,
nodeid=os.path.join(THIS_PACKAGE, '{}_conf.py'.format(name))))
result.append(Module(os.path.join(parent.fspath, THIS_PACKAGE, 'test_common.py'), parent,
nodeid=tests_node_id))
return pytest_runtest_protocol, pytest_collect_file
在tests/impl1/conftest.py
中我有
@pytest.fixture
def impl1_instance():
return Impl1()
pytest_runtest_protocol, pytest_collect_file = create_instance_hooks(impl1_instance, 'impl1')
在tests/impl2/conftest.py
中我有
@pytest.fixture
def impl2_instance():
return Impl2()
pytest_runtest_protocol, pytest_collect_file = create_instance_hooks(impl2_instance, 'impl2')
因此,基本上,当收集了tests/implN
个测试时,pytest_collect_file
钩子会添加来自tests/common/test_common.py
的测试
然后运行它们时,pytest_runtest_protocol
钩子会将implN_instance
固定装置添加为实例固定装置。因此,如果我只运行impl1或impl2,则运行一组测试,而如果我仅运行pytest测试,则有两组具有适当夹具的测试