为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

慕尼黑8549860 2022-05-19 18:44:32
我想对多个夹具值运行同一组测试,但我不想在夹具定义中“硬编码”这些值。我的用例是一个具有多个实现的接口,我想在每个实现上运行相同的测试。例如,my_code.pyclass Interface:   def method():      passclass Impl1(Interface):   def method():      return 1class Impl2(Interface):   def method():      return 2test_interface.py:def test_method(instance: Interface):    assert type(instance.method()) == inttest_impl1.pyfrom my_code import Impl1@pytest.fixturedef instance():    return Impl1()test_impl2.pyfrom my_code import Impl2@pytest.fixturedef 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 回答

?
心有法竹

TA贡献1866条经验 获得超5个赞

终于解决了这个问题,但不确定这是否是可靠的解决方案。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 测试,则有两组带有适当夹具的测试


查看完整回答
反对 回复 2022-05-19
  • 1 回答
  • 0 关注
  • 89 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信