使用 fixture return 值作为 mark.parametrize() 中的值
using fixture return value as value in mark.parametrize()
我的问题是 - 是否可以使用夹具中的 return 值作为参数化中的值?
问题是 - 我想动态获取参数化的可能值(例如,虚拟服务器上的可用系统)。当其中一个装置创建虚拟服务器时,我可以访问这些。测试看起来像这样(伪代码):
[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
这样每次session添加一个server,然后所有的测试运行都在上面,session结束后,server被移除。但是有没有一种方法可以在不显式列出它们的情况下获取 @pytest.mark.parametrize 中的可用系统(静态地作为参数化列表),使用会话开始时添加的服务器方法?这样每个系统都会 运行 在单独的测试中。
我尝试在另一个夹具中使用 test_server,然后 returning 列表(同样的方式 test_server 被 test_server 夹具 returned,但我不能将其用作参数化中的值 - 因为在任何测试中调用 test_server fixture 之前都会评估装饰器,并且获取列表取决于 test_server fixture.
这将是理想的:
[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)
这只是一个非常基本的示例,在我的测试中,我需要根据多个场景和值进行参数化,当我静态执行时,我最终会得到巨大的数组。
但原理保持不变 - 基本上:我可以在使用此夹具 运行s 的第一次测试之前调用夹具,或者 pytest.mark.parametrize() 如何访问夹具值?
我想你可能无法直接达到你想要的。因为@pytest.mark.parametrize
是在采集的时候调用,fixture会在采集完成后调用。
但我有另一种方法来实现类似的结果,主要是通过扩展 pytest 插件 pytest_generate_tests
和使用方法 metafunc.parametrize
。
https://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
不好的是,每次使用 fixture 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)
我能够解决类似的问题,我必须生成用于动态参数化的测试数据:
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]
...
这样就可以支持动态添加参数了,只是你需要预先确定测试的数量。
我的问题是 - 是否可以使用夹具中的 return 值作为参数化中的值? 问题是 - 我想动态获取参数化的可能值(例如,虚拟服务器上的可用系统)。当其中一个装置创建虚拟服务器时,我可以访问这些。测试看起来像这样(伪代码):
[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
这样每次session添加一个server,然后所有的测试运行都在上面,session结束后,server被移除。但是有没有一种方法可以在不显式列出它们的情况下获取 @pytest.mark.parametrize 中的可用系统(静态地作为参数化列表),使用会话开始时添加的服务器方法?这样每个系统都会 运行 在单独的测试中。
我尝试在另一个夹具中使用 test_server,然后 returning 列表(同样的方式 test_server 被 test_server 夹具 returned,但我不能将其用作参数化中的值 - 因为在任何测试中调用 test_server fixture 之前都会评估装饰器,并且获取列表取决于 test_server fixture.
这将是理想的:
[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)
这只是一个非常基本的示例,在我的测试中,我需要根据多个场景和值进行参数化,当我静态执行时,我最终会得到巨大的数组。
但原理保持不变 - 基本上:我可以在使用此夹具 运行s 的第一次测试之前调用夹具,或者 pytest.mark.parametrize() 如何访问夹具值?
我想你可能无法直接达到你想要的。因为@pytest.mark.parametrize
是在采集的时候调用,fixture会在采集完成后调用。
但我有另一种方法来实现类似的结果,主要是通过扩展 pytest 插件 pytest_generate_tests
和使用方法 metafunc.parametrize
。
https://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
不好的是,每次使用 fixture 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)
我能够解决类似的问题,我必须生成用于动态参数化的测试数据:
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]
...
这样就可以支持动态添加参数了,只是你需要预先确定测试的数量。