Pytest参数化详解-上

简介: Pytest参数化详解-上
  1. @pytest.fixture():允许对 fixture 函数进行参数化
  2. @pytest.mark.parametrize:允许在测试函数、方法进行参数化
  3. Pytest_generate_tests:允许定义自定义参数化方案和扩展

前面已经讲过fixture的参数化了,本章再次复习一下!

fixtrue参数化

"""conftest.py"""
import pytest
user = ('TOM', 'JEMI', 'JEERY')
age = (12, 15, 18)
@pytest.fixture(params=user)
def user_data(request):
    yield request.param
@pytest.fixture(params=age)
def age_data(request):
    yield request.param
"""test_a.py"""
def test_user(user_data):
    print("TEST USER",user_data)
def test_age(age_data):
    print("TEST DATA",age_data)
# def test_user_data(user_data,age_data):
#     print("test_user and test_age",user_data,age_data)
"""
Case/test_a.py::test_user[TOM] TEST USER TOM
PASSED
Case/test_a.py::test_user[JEMI] TEST USER JEMI
PASSED
Case/test_a.py::test_user[JEERY] TEST USER JEERY
PASSED
Case/test_a.py::test_age[12] TEST DATA 12
PASSED
Case/test_a.py::test_age[15] TEST DATA 15
PASSED
Case/test_a.py::test_age[18] TEST DATA 18
PASSED
"""

还有一种情况就是上述代码的注释部分,运行后,它会将各种组合都跑一遍:

Case/test_a.py::test_user_data[TOM-12] test_user and test_age TOM 12
PASSED
Case/test_a.py::test_user_data[TOM-15] test_user and test_age TOM 15
PASSED
Case/test_a.py::test_user_data[TOM-18] test_user and test_age TOM 18
PASSED
Case/test_a.py::test_user_data[JEMI-12] test_user and test_age JEMI 12
PASSED
Case/test_a.py::test_user_data[JEMI-15] test_user and test_age JEMI 15
PASSED
Case/test_a.py::test_user_data[JEMI-18] test_user and test_age JEMI 18
PASSED
Case/test_a.py::test_user_data[JEERY-12] test_user and test_age JEERY 12
PASSED
Case/test_a.py::test_user_data[JEERY-15] test_user and test_age JEERY 15
PASSED
Case/test_a.py::test_user_data[JEERY-18] test_user and test_age JEERY 18
PASSED

parametrize参数化

入门级

import pytest
user = ('TOM', 'JEMI', 'JEERY')
@pytest.mark.parametrize('user',user)
def test_parametrize(user):
    print("USER",user)
  1. 第一个参数为名称,在后面的方法中会使用到,如 param1
  2. 第二个参数为值,任何数据类型都可以,不过有些需要做一些处理,例如字典:
import pytest
user = {"name1":'TOM', "name2":'JEMI', "name3":'JEERY'}
@pytest.mark.parametrize('user',user.values())
def test_parametrize(user):
    print("USER",user)
"""
Case/test_a.py::test_parametrize[TOM] USER TOM
PASSED
Case/test_a.py::test_parametrize[JEMI] USER JEMI
PASSED
Case/test_a.py::test_parametrize[JEERY] USER JEERY
PASSED
"""

你大可以理解为parametrize走了一个for循环的过程,将只循环出来然后赋值给了自定义的变量。

多参数

import pytest
users = [('TOM',12), ('JEMI',15), ('JEER',18)]
@pytest.mark.parametrize('user,age',users)
def test_parametrize(user,age):
    print("USER AND AGE",user,age)
"""
Case/test_a.py::test_parametrize[TOM-12] USER AND AGE TOM 12
PASSED
Case/test_a.py::test_parametrize[JEMI-15] USER AND AGE JEMI 15
PASSED
Case/test_a.py::test_parametrize[JEER-18] USER AND AGE JEER 18
PASSED
"""

与fixture结合

import pytest
sex = ['男','女','女']
@pytest.fixture(params=sex)
def sex_data(request):
    yield request.param
users = [('TOM',12), ('JEMI',15), ('JEER',18)]
@pytest.mark.parametrize('user,age',users)
def test_parametrize(user,age,sex_data):
    print("USER AND AGE",user,age,sex_data)
Case/test_a.py::test_parametrize[\u7537-TOM-12] USER AND AGE TOM 12 男
PASSED
Case/test_a.py::test_parametrize[\u7537-JEMI-15] USER AND AGE JEMI 15 男
PASSED
Case/test_a.py::test_parametrize[\u7537-JEER-18] USER AND AGE JEER 18 男
PASSED
Case/test_a.py::test_parametrize[\u59730-TOM-12] USER AND AGE TOM 12 女
PASSED
Case/test_a.py::test_parametrize[\u59730-JEMI-15] USER AND AGE JEMI 15 女
PASSED
Case/test_a.py::test_parametrize[\u59730-JEER-18] USER AND AGE JEER 18 女
PASSED
Case/test_a.py::test_parametrize[\u59731-TOM-12] USER AND AGE TOM 12 女
PASSED
Case/test_a.py::test_parametrize[\u59731-JEMI-15] USER AND AGE JEMI 15 女
PASSED
Case/test_a.py::test_parametrize[\u59731-JEER-18] USER AND AGE JEER 18 女
PASSED

\u7537以及\u59730是Unicode编码,可以不需要理会。不论时候结合fixture,只要带fixture多参数化作用在同一函数就会带来了不一样的结果,也造成了非预期结果,两个取合适的就行。

编码问题

如果非常介意Unicode编码问题,那么如下的解决方案:

"""conftest.py中修改"""
def pytest_collection_modifyitems(items):
    """
    测试用例收集完成时,将收集到的item的name和nodeid的中文显示在控制台上
    :return:
    """
    for item in items:
        item.name = item.name.encode("utf-8").decode("unicode_escape")
        item._nodeid = item.nodeid.encode("utf-8").decode("unicode_escape")

ids取别名

与fixture有些近似,还是那句话,如果有编码问题,采用上面的方式。

import pytest
sex = ['男','女','女']
@pytest.fixture(params=sex,ids=["性别1","性别2","性别3"])
def sex_data(request):
    yield request.param
users = [('TOM',12), ('JEMI',15), ('JEER',18)]
@pytest.mark.parametrize('user,age',users,ids=["用户1","用户2","用户3"])
def test_parametrize(user,age,sex_data):
    print("USER AND AGE",user,age,sex_data)
Case/test_a.py::test_parametrize[性别1-用户1] USER AND AGE TOM 12 男
PASSED
Case/test_a.py::test_parametrize[性别1-用户2] USER AND AGE JEMI 15 男
PASSED
Case/test_a.py::test_parametrize[性别1-用户3] USER AND AGE JEER 18 男
PASSED
Case/test_a.py::test_parametrize[性别2-用户1] USER AND AGE TOM 12 女
PASSED
Case/test_a.py::test_parametrize[性别2-用户2] USER AND AGE JEMI 15 女
PASSED
Case/test_a.py::test_parametrize[性别2-用户3] USER AND AGE JEER 18 女
PASSED
Case/test_a.py::test_parametrize[性别3-用户1] USER AND AGE TOM 12 女
PASSED
Case/test_a.py::test_parametrize[性别3-用户2] USER AND AGE JEMI 15 女
PASSED
Case/test_a.py::test_parametrize[性别3-用户3] USER AND AGE JEER 18 女
PASSED

这样就能比较明白的看到了,不过显然,看如上的结果,每个用户三种性别显然不合适。所以,在用法上,切记注意了。此外,它可以跟fixture一样,在ids中使用推导式哦

多个parametrize作用在同一个用例

与多个fixture作用在同一个函数上类似

users = ['TOM', 'JEMI', 'JEER']
ages = [15, 18, 20]
@pytest.mark.parametrize('user', users, ids=["用户1", "用户2", "用户3"])
@pytest.mark.parametrize('age', ages, ids=["年龄1", "年龄2", "年龄3"])
def test_parametrize(user, age):
    print("USER AND AGE", user, age)
Case/test_a.py::test_parametrize[年龄1-用户1] USER AND AGE TOM 15
PASSED
Case/test_a.py::test_parametrize[年龄1-用户2] USER AND AGE JEMI 15
PASSED
Case/test_a.py::test_parametrize[年龄1-用户3] USER AND AGE JEER 15
PASSED
Case/test_a.py::test_parametrize[年龄2-用户1] USER AND AGE TOM 18
PASSED
Case/test_a.py::test_parametrize[年龄2-用户2] USER AND AGE JEMI 18
PASSED
Case/test_a.py::test_parametrize[年龄2-用户3] USER AND AGE JEER 18
PASSED
Case/test_a.py::test_parametrize[年龄3-用户1] USER AND AGE TOM 20
PASSED
Case/test_a.py::test_parametrize[年龄3-用户2] USER AND AGE JEMI 20
PASSED
Case/test_a.py::test_parametrize[年龄3-用户3] USER AND AGE JEER 20
PASSED

也是把参数中的每一个值都进行的匹配。所以说,这种近似类似的写法,在不同的时候选择不同的用法。

间接参数化

@pytest.fixture
def data(request):
    return request.param
@pytest.mark.parametrize("data",["清安",'拾贰'],indirect=True)
def test_data(data):
    print("name:",data)
Case/test_a.py::test_data[清安] name: 清安
PASSED
Case/test_a.py::test_data[拾贰] name: 拾贰
PASSED

有发现这与上面所讲的叠加参数化以及混合使用的区别了吗。这样的方式可以帮助我们更加精准的执行想要的参数用例,而不是存在一些混合的场景参数。此外,你还可以直接在data函数中做数据处理及运算,然后将返回值给到测试用例,一起看看:

@pytest.fixture
def data(request):
    return request.param * 2
@pytest.mark.parametrize("data",["清安",'拾贰'],indirect=True)
def test_data(data):
    print("name:",data)
"""
Case/test_a.py::test_data[清安] name: 清安清安
PASSED
Case/test_a.py::test_data[拾贰] name: 拾贰拾贰
PASSED
"""

指定间接参数

@pytest.fixture
def data(request):
    return request.param * 2
@pytest.fixture
def age(request):
    return request.param * 2
information = [('清安',8), ('拾贰',9)]
@pytest.mark.parametrize("data,age",information,indirect=['age'])
def test_data(data,age):
    print("name:",data)
    print("age:",age)
"""
Case/test_a.py::test_data[清安-8] name: 清安
age:16
PASSED
Case/test_a.py::test_data[拾贰-9] name: 拾贰
age:18
PASSED
"""

看到了吗,indirect可以指定某个fixture运行,同时不影响参数传递。

为单个参数化测试设置标记或测试ID

import pytest
user = {"username1":"QINGAN",'username2':"清安"}
@pytest.mark.parametrize(
    "data,name",[
        ("10+2", 12),
        pytest.param("清"+"安",user['username2'], marks=pytest.mark.basic),
        pytest.param("QINGAN",user['username1'],marks=pytest.mark.basic,id="basic_user1")
    ]
)
def test_eval(data,name):
    assert data == name
    print(data,name)
"""
Case/test_a.py::test_eval[清安-清安] 清安 清安
PASSED
Case/test_a.py::test_eval[basic_user1] QINGAN QINGAN
PASSED
======================= 2 passed, 1 deselected in 0.02s =======================
"""

记得在pytest.ini亦或者其他配置文件中注册mark标志。此处是只跑了basic标志的,所以只有两个用例。

这里有新的知识点,也就是pytest.param,以及pytest.param中的id。看似写的多,其实真的写的多,实际应用上,很少会这样写。

目录
相关文章
|
6月前
|
测试技术
Pytest参数化用例
`Pytest`的参数化功能用于通过参数生成和执行多个测试用例。使用`@pytest.mark.parametrize`装饰器,可传入不同数据,如单参数或多个参数,并可设置`ids`为用例命名。例如,一个搜索功能测试会根据提供的关键词列表动态生成用例。另外,通过创建`conftest.py`文件并定义函数,可以显示中文用例名称。同时,可以利用笛卡尔积实现更复杂的参数组合。
51 0
|
测试技术 数据处理
Pytest参数化详解-下
Pytest参数化详解-下
98 0
|
测试技术 Python
pytest--运行指定的测试和参数化
pytest--运行指定的测试和参数化
|
测试技术
09-pytest-parametrize参数化
09-pytest-parametrize参数化
|
JSON 测试技术 数据安全/隐私保护
06-Httprunner-参数化
06-Httprunner-参数化
|
测试技术 Python
python生成器+pytest实现参数化
定义:生成器是由函数+yield关键字创造出来的写法
|
测试技术 Python
pytest学习和使用17-Pytest如何重复执行用例?(pytest-repeat)
pytest学习和使用17-Pytest如何重复执行用例?(pytest-repeat)
140 0
pytest学习和使用17-Pytest如何重复执行用例?(pytest-repeat)
|
测试技术
pytest学习和使用5-Pytest和Unittest中的断言如何使用?
pytest学习和使用5-Pytest和Unittest中的断言如何使用?
92 0
pytest学习和使用5-Pytest和Unittest中的断言如何使用?