我正在尝试使用 Pytest 编写动态测试套件,其中测试数据保存在单独的文件中,例如YAML 文件或 .csv。我想运行多个测试,所有这些测试都是从同一个文件进行参数化的。假设我有一个测试文件test_foo.py
,看起来像这样:
import pytest
@pytest.mark.parametrize("num1, num2, output", ([2, 2, 4], [3, 7, 10], [48, 52, 100]))
def test_addnums(num1, num2, output):
assert foo.addnums(num1, num2) == output
@pytest.mark.parametrize("foo, bar", ([1, 2], ['moo', 'mar'], [0.5, 3.14]))
def test_foobar(foo, bar):
assert type(foo) == type(bar)
使用参数化装饰器,我可以在 pytest 中运行多个测试,并且按预期工作:
test_foo.py::test_addnums[2-2-4] PASSED
test_foo.py::test_addnums[3-7-10] PASSED
test_foo.py::test_addnums[48-52-100] PASSED
test_foo.py::test_foobar[1-2] PASSED
test_foo.py::test_foobar[moo-mar] PASSED
test_foo.py::test_foobar[0.5-3.14] PASSED
但我想动态地参数化这些测试。我的意思是,我想编写测试数据所有测试在一个单独的文件中,以便当我运行 pytest 时,它将应用我写入每个测试函数的所有测试数据。假设我有一个类似于以下内容的 YAML 文件:
test_addnums:
params: [num1, num2, output]
values:
- [2, 2, 4]
- [3, 7, 10]
- [48, 52, 100]
test_foobar:
params: [foo, bar]
values:
- [1, 2]
- [moo, mar]
- [0.5, 3.14]
然后,我想要读取此 YAML 文件并使用该数据来参数化测试文件中的所有测试函数。
我知道pytest_generate_tests
钩子,我一直在尝试使用它来动态加载测试。我尝试添加之前传递到的相同参数和数据值parametrize
装饰器进入metafunc.parametrize
hook:
def pytest_generate_tests(metafunc):
metafunc.parametrize("num1, num2, output", ([2, 2, 4], [3, 7, 10], [48, 52, 100]))
metafunc.parametrize("foo, bar", ([1, 2], ['moo', 'mar'], [0.5, 3.14]))
def test_addnums(num1, num2, output):
assert foo.addnums(num1, num2) == output
def test_foobar(foo, bar):
assert type(foo) == type(bar)
然而,这不起作用,因为 pytest 尝试将测试数据应用于每个函数:
collected 0 items / 1 error
=============================== ERRORS ================================
____________________ ERROR collecting test_foo.py _____________________
In test_addnums: function uses no argument 'foo'
======================= short test summary info =======================
ERROR test_foo.py
!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!
========================== 1 error in 0.16s ===========================
我想知道的是:如何动态参数化多次测试使用pytest?我使用 pdb 内省了 pytest,据我所知,metafunc
只知道您在文件中定义的第一个测试。在我上面的例子中,test_addnums
首先定义,所以当我打印时vars(metafunc)
在 pdb 调试器中,它显示这些值:
(Pdb) pp vars(metafunc)
{'_arg2fixturedefs': {},
'_calls': [<_pytest.python.CallSpec2 object at 0x7f4330b6e860>,
<_pytest.python.CallSpec2 object at 0x7f4330b6e0b8>,
<_pytest.python.CallSpec2 object at 0x7f4330b6e908>],
'cls': None,
'config': <_pytest.config.Config object at 0x7f43310dbdd8>,
'definition': <FunctionDefinition test_addnums>,
'fixturenames': ['num1', 'num2', 'output'],
'function': <function test_addnums at 0x7f4330b5a6a8>,
'module': <module 'test_foo' from '<PATH>/test_foo.py'>}
但如果我换个方向test_foobar
and test_addnums
函数,并颠倒顺序parametrize
调用,它显示有关的信息test_foobar
反而。
(Pdb) pp vars(metafunc)
{'_arg2fixturedefs': {},
'_calls': [<_pytest.python.CallSpec2 object at 0x7f6d20d5e828>,
<_pytest.python.CallSpec2 object at 0x7f6d20d5e860>,
<_pytest.python.CallSpec2 object at 0x7f6d20d5e898>],
'cls': None,
'config': <_pytest.config.Config object at 0x7f6d212cbd68>,
'definition': <FunctionDefinition test_foobar>,
'fixturenames': ['foo', 'bar'],
'function': <function test_foobar at 0x7f6d20d4a6a8>,
'module': <module 'test_foo' from '<PATH>/test_foo.py'>}
所以看起来 metafunc 实际上并没有在我的测试文件中存储有关每个测试函数的信息。因此我不能使用fixturenames
or function
属性,因为它们仅适用于一个特定函数,而不是所有函数。
如果是这种情况,那么我如何访问所有其他测试函数并单独参数化它们?