pytest文档69-Hook函数之参数化pytest_generate_tests
前言
pytest 实现参数化有三种方式
pytest.fixture() 使用 fixture 传 params 参数实现参数化
@ pytest.mark.parametrize 允许在测试函数或类中定义多组参数,在用例中实现参数化
pytest_generate_tests 允许定义自定义参数化方案或扩展。
pytest_generate_tests
pytest_generate_tests 在测试用例参数化收集前调用此钩子函数,根据测试配置或定义测试函数的类或模块中指定的参数值生成测试用例,
可以使用此钩子实现自定义参数化方案或扩展,相关文档参考官方文档https://docs.pytest.org/en/latest/parametrize.html#pytest-generate-tests
有时您可能想要实现自己的参数化方案或实现某种动态性来确定 fixture 的参数或范围。为此,可以使用pytest_generate_tests在收集测试函数时调用的钩子。通过传入的 metafunc 对象,您可以检查请求的测试上下文,最重要的是,您可以调用 metafunc.parametrize() 引起参数化。
例如,假设我们要运行一个测试,并接受要通过新的 pytest 命令行选项设置的字符串输入。让我们首先编写一个接受 stringinput 函数参数的简单测试:
# content of test_strings.py
def test_valid_string(stringinput):
assert stringinput.isalpha()
现在,我们添加一个conftest.py文件,其中包含命令行选项和测试函数的参数化:
# content of conftest.py
def pytest_addoption(parser):
parser.addoption(
"--stringinput",
action="append",
default=[],
help="list of stringinputs to pass to test functions",
)
def pytest_generate_tests(metafunc):
if "stringinput" in metafunc.fixturenames:
metafunc.parametrize("stringinput", metafunc.config.getoption("stringinput"))
如果现在传递两个stringinput值,则测试将运行两次:
$ pytest -q --stringinput="hello" --stringinput="world" test_strings.py
.. [100%]
2 passed in 0.12s
我们还使用一个stringinput运行,这将导致测试失败:
$ pytest -q --stringinput="!" test_strings.py
F [100%]
================================= FAILURES =================================
___________________________ test_valid_string[!] ___________________________
stringinput = '!'
def test_valid_string(stringinput):
> assert stringinput.isalpha()
E AssertionError: assert False
E + where False = <built-in method isalpha of str object at 0xdeadbeef>()
E + where <built-in method isalpha of str object at 0xdeadbeef> = '!'.isalpha
test_strings.py:4: AssertionError
========================= short test summary info ==========================
FAILED test_strings.py::test_valid_string[!] - AssertionError: assert False
1 failed in 0.12s
不出所料,我们的测试功能失败。
如果您未指定字符串输入,则将跳过它,因为 metafunc.parametrize()将使用空参数列表来调用它:
$ pytest -q -rs test_strings.py
s [100%]
========================= short test summary info ==========================
SKIPPED [1] test_strings.py: got empty parameter set ['stringinput'], function test_valid_string at $REGENDOC_TMPDIR/test_strings.py:2
1 skipped in 0.12s
请注意,当metafunc.parametrize使用不同的参数集多次调用时,这些集合中的所有参数名称都不能重复,否则会引发错误。
更多的参数化案例参考https://docs.pytest.org/en/latest/example/parametrize.html#paramexamples
使用示例
在 conftest.py 自定义参数化的钩子, 判断当测试用例传了 param 参数,就让它生成参数化的用例
def pytest_generate_tests(metafunc):
""" generate (multiple) parametrized calls to a test function."""
if "param" in metafunc.fixturenames:
metafunc.parametrize("param",
metafunc.module.test_data,
ids=metafunc.module.names,
scope="function")
test_parm.py相关的测试数据和用例内容,names是用例的名称,test_data是测试数据
import requests
# 作者-上海悠悠 QQ交流群:717225969
# blog地址 https://www.cnblogs.com/yoyoketang/
# 用例的id名称
names = ["login nam1", "login name2"]
# 测试数据 list of dict
test_data = [{
"url": "http://49.235.x.x:5000/api/v1/login/",
"method": "POST",
"headers":
{
"Content-Type": "application/json"
},
"json":
{
"username": "test",
"password": "123456"
}
},
{
"url": "http://49.235.x.x:5000/api/v1/login/",
"method": "POST",
"headers":
{
"Content-Type": "application/json"
},
"json":
{
"username": "test",
"password": "123456"
}
}
]
def test_login(param):
r = requests.session().request(**param)
print(r.text)
这样运行会,自动生成2条测试用例
================= test session starts ===============
platform win32 -- Python 3.6.6, pytest-4.5.0, py-1.9.0, pluggy-0.13.1
rootdir: D:\
collected 2 items
..\test_param.py
{"code": 0, "msg": "login success!", "username": "test", "token": "81ae10099feaca6f0af5ba122444bea2a83a2dc9"}
.{"code": 0, "msg": "login success!", "username": "test", "token": "1ccfb99fd68f22da66c95660702af22d64108067"}
.
=============== 2 passed in 0.62 seconds ===============
上面是把测试数据和代码放一起,想实现代码和数据分离的话,上面的 names 和 test_data 测试数据写到 yaml 文件,写个函数去读取 yaml 文件的数据。
2021年第六期《python接口自动化+测试开发》课程,1月9号开学(火热报名中!)
本期上课时间:1月9号-4月18号,每周六、周日晚上20:30-22:30