【问题标题】:using fixture return value as value in mark.parametrize()使用夹具返回值作为 mark.parametrize() 中的值
【发布时间】:2016-06-22 15:37:27
【问题描述】:

我的问题是 - 是否可以使用来自夹具的返回值作为参数化的值? 问题是 - 我想动态获取参数化的可能值(例如,虚拟服务器上的可用系统)。当其中一个装置创建虚拟服务器时,我可以访问这些。测试看起来像这样(伪代码):

[conftest.py]

@pytest_fixture(scope='session')
def test_server(request):
    test_server = Server([default_params])
    test_server.add()
    def fin():
        test_server.delete()
    request_addfinalizer(fin)
    return test_server()

[tests.py]

def test_basic_server(test_server):
    systems = test.server.get_available_systems()
    for system in systems:
        test_server.install(system)
        test_server.run_checks()
        test_server.uninstall(system)

def test_other(test_server):
    [other tests]

etc

这样,为每个会话添加一个服务器,然后在其上运行所有测试,会话结束后,服务器被删除。但是有没有办法使用会话开始时添加的服务器方法来获取@pytest.mark.parametrize 中的可用系统而不显式列出它们(静态地作为参数化中的列表)?这样每个系统都会在单独的测试中运行。

我尝试在另一个夹具中使用 test_server 然后返回列表(与 test_server 夹具返回 test_server 的方式相同,但我不能将其用作参数化中的值 - 因为在任何测试中调用 test_server 夹具之前评估装饰器,获取列表取决于 test_server 夹具。

这将是理想的:

[tests.py]

@pytest.mark.parametrize('system',[systems_list <- dynamically generated
                                             when the server is created])

def test_basic_server(test_server,system):
    test_server.install(system)
    test_server.run_checks()
    test_server.uninstall(system)

这只是一个非常基本的示例,在我的测试中,我需要根据多个场景和值进行参数化,当我静态执行时,我最终会得到巨大的数组。

但原理保持不变 - 基本上:我可以在使用此夹具的第一次测试运行之前调用夹具,或者 pytest.mark.parametrize() 如何访问夹具值?

【问题讨论】:

    标签: python pytest


    【解决方案1】:

    我认为你可能无法直接实现你想要的。因为@pytest.mark.parametrize在采集过程中被调用,而fixtures会在采集完成后被调用。

    但是我有另一种方法可以达到类似的结果,主要是通过扩展pytest插件pytest_generate_tests和使用方法metafunc.parametrizehttps://pytest.org/latest/parametrize.html#basic-pytest-generate-tests-example

    这是我的解决方案。 在conftest.py中

    class System(object):
        def __init__(self, name):
            self.name = name
    
        def __repr__(self):
            return "<System '{}'>".format(self.name)
    
    def get_available_systems():
        return [System('A'), System('B'), System('C')]
    
    
    def pytest_generate_tests(metafunc):
        if 'system' in metafunc.fixturenames:
            available_systems = get_available_systems()
    
            metafunc.parametrize('system', available_systems)
    

    在测试文件中:

    def test_basic_server(system):
        print(system)
    

    这是输出,您将可以访问测试中的每个系统。

    collected 3 items
    
    test_01.py::test_basic_server[system0] <System 'A'>
    PASSED
    test_01.py::test_basic_server[system1] <System 'B'>
    PASSED
    test_01.py::test_basic_server[system2] <System 'C'>
    PASSED
    

    不好的是,每次使用夹具system 时都会调用get_available_systems,这不是你想要的。但是我认为添加一些额外的逻辑来使查询逻辑只执行一次并不难。

    例如:

    def pytest_generate_tests(metafunc):
        if 'system' in metafunc.fixturenames:
            if hasattr(metafunc.config, 'available_systems'):
                available_systems = metafunc.config.available_systems
            else:
                available_systems = get_available_systems()
                metafunc.config.available_systems = available_systems
            metafunc.parametrize('system', available_systems)
    

    【讨论】:

    • 是的,我一直在研究 metafunc,这是一种有效的方法,但仍然需要在测试开始之前添加另一台服务器来收集系统列表。 IRL 我必须考虑多种方法(超过 20 种),它们根据可用的内容返回动态列表。平均而言,这意味着超过 300 个案例,现在作为单个测试运行 - 因此您可以了解为什么如果参数化可以吞下列表并生成单独的案例会很好。不过,我会更深入地研究它,也许使用 metafunc 我会到达某个地方。谢谢你:)
    • 实际上,如果我在评估 conftest.py 期间设法(物理上)添加了一个服务器,然后访问它的方法来获取我需要的列表,存储它们然后在 pytest_generate_tests() 中使用这正是我所需要的 :) 不是最干净的解决方案,但这可以完成工作,而且我不必维护数百个在任何给定时刻都可能发生变化的变量。
    • 是的,我认为将不同服务器的测试作为单独的测试运行是个好主意(通过使用parametrize),这使得测试结果更清晰,更容易找到失败原因。也希望知道任何更整洁的解决方案
    【解决方案2】:

    我能够解决一个类似的问题,我必须生成用于动态参数化的测试数据:

    class TestFilters(object):
     cls_testdata1 = []
    
    def setup_class(cls):
     r = []
     for i in range(5):
       r.append((x, y, z))
     TestFilters.cls_testdata1 = r
    
    @pytest.mark.parametrize("filter_id", list(range(5)))
    def test_func(self, filter_id):
        params = TestFilters.cls_testdata1[filter_id]
    

    ...

    这将支持动态添加参数,只是您需要预先确定测试的数量。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-25
      • 2015-08-27
      • 2017-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多