是否可以动态更新参数化灯具的参数?

时间:2019-09-04 23:50:02

标签: python pytest

我想对多个灯具值运行相同的测试集,但是我不想在灯具定义中“硬编码”这些值。

我的用例是具有多个实现的接口,并且我想在每个实现上运行相同的测试。

例如,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 如果我的实现完全在其他程序包中怎么办?

简而言之,我想针对固定装置列表中的每个值重用我的测试,但是我想在运行时更改此固定装置列表(例如,取决于可用的实现)

1 个答案:

答案 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测试,则有两组具有适当夹具的测试

相关问题