一、参数化简介
pytest允许在多个级别启用测试参数化:
- @pytest.mark.parametrize 允许在测试函数或类中定义多组参数和fixtures
- @pytest.fixture() 允许fixture有参数化功能
- pytest_generate_tests 允许定义自定义参数化方案或扩展(拓展)
二、@pytest.mark.parametrize
有这样一个场景,登录的测试用例,共同的特点是,它们测试步骤是一模一样的,只是输入的数据(用户名、密码)不同,要检查的输出数据(错误提示)不同。这批测试用例,就是典型的 可以用 数据驱动
相同的测试步骤
测试参数数据不同
分离
开来,以后增加新的测试用例,只需要修改数据。这就是数据驱动。
这种情况可以使用 pytest 用例 的 数据驱动格式,只需如下定义即可:
import pytest
def login(username,password):
if username == "zhangwuj" and password == "123456":
return "登录成功"
else:
return "用户名或者密码错误"
class Test_pass03:
@pytest.mark.parametrize('username, password, expectedalert', [
('lisi', '88888888', '请输入用户名'),
('zhangsan', None, '请输入密码')
])
def test_UI_0005(self, username, password, expectedalert):
alertText = login(username, password)
assert alertText == expectedalert
这样,我们就不需要定义那么多的测试用例方法了, 而且测试数据也可以集中存放。参考pytest官方文档,之后结果如下:
三、fixture 传参数 request
为了提高复用性,在编写测试用例的时候,会用到不同的fixture,比如:项目中的登录操作,大部分的用例的前置条件都是登录,假设不同的用例想登录不同的测试账号,那么登录fixture就不能把账号写死,需要通过传参的方式来完成登录操作
3.1.传单个参数
准备test_case16.py,代码如下:
import pytest
@pytest.fixture()
def login(request):
"""
将函数 login 标记为一个 Pytest fixture。Pytest fixture 是一个用于提供测试数据或测试环境的函数或方法。在此处,login 是一个 fixture,将在每次测试调用之前运行。
:param request: 是一个特殊的 fixture 参数,它代表当前测试用例的请求对象。可以通过该对象获取测试用例参数和其他信息。
:return:
"""
# 获取参数:获取测试用例参数的值。在 @pytest.mark.parametrize 注解中,通过 data 列表传递的每个值都会依次赋给 request.param
name = request.param
print(f"*************本次登录用户名{name}*************")
# 测试用例参数 name 作为 fixture 的返回值
return name
data = ["张三", "李四"]
ids = [f"login name is:{name}" for name in data]
# "login":这是测试用例的参数名。
# data:这是一个包含测试用例参数的列表,用于参数化测试。每个测试用例都会按顺序取值。
# ids=ids:这是一个包含参数标识的列表,用于在测试报告中显示可读性更高的标识。
# indirect=True:这个参数的值为 True,表明 login 参数是一个 fixture。
@pytest.mark.parametrize("login", data, ids=ids, indirect=True)
# login 参数将会从 login fixture 中获取值
def test_order(login):
print(f"本次登录的账户是:{login}")
assert login == "李四"
执行结果如下:
注意:
- 添加 indirect=True 参数是为了把 login 当成一个函数去执行,而不是一个参数,并且将data当做参数传入函数
- def test_name(login) ,这里的login是获取fixture返回的值
3.2.多个参数
传入多个参数,准备代码如下:
import pytest
@pytest.fixture()
def logins(request):
params = request.param
# 多个参数传入的是字典,也要通过键获取值
print(f"账户是:{params['username']},密码是:{params['password']}")
return params
# 准备参数化的数据,多个参数需要以字典的形式传入
data = [{"username": "Augus", "password": "123321"}, {"username": "ls", "password": "123456"}]
@pytest.mark.parametrize("logins", data, indirect=True)
def test_user_login(logins):
print(f"账户是:{logins['username']},密码是:{logins['password']}")
执行结果如下:
注意:如果需要传多个参数,需要通过字典去传
3.3.多个fixture(只加一个装饰器)推荐使用
可以使用多个fixtrue处理多个参数,只用一个装饰器给用例设置,代码如下:
import pytest
# 处理账户
@pytest.fixture()
def logins_username(request):
username = request.param
# 多个参数传入的是字典,也要通过键获取值
print(f"账户是:{username}")
return username
# 处理密码
@pytest.fixture()
def logins_password(request):
password = request.param
# 多个参数传入的是字典,也要通过键获取值
print(f"密码是:{password}")
return password
# 准备参数化的数据
data = [("Augus", "123321"), ("ls", "123456")]
@pytest.mark.parametrize("logins_username, logins_password", data, indirect=True)
def test_user_login(logins_username, logins_password):
print(f"账户是:{logins_username},密码是:{logins_password}")
代码执行如下:
3.4.多个fixture(叠加装饰器)
可以使用多个fixtrue处理多个参数,用多个装饰器给用例设置,代码如下:
import pytest
# 处理账户
@pytest.fixture()
def logins_username(request):
username = request.param
# 多个参数传入的是字典,也要通过键获取值
print(f"账户是:{username}")
return username
# 处理密码
@pytest.fixture()
def logins_password(request):
password = request.param
# 多个参数传入的是字典,也要通过键获取值
print(f"密码是:{password}")
return password
# 准备参数化的数据,多个参数需要以字典的形式传入
name = ["Augus", "ls"]
pwd = ["123321", "123456"]
@pytest.mark.parametrize("logins_username", name, indirect=True)
@pytest.mark.parametrize("logins_password", pwd, indirect=True)
def test_user_login(logins_username, logins_password):
print(f"账户是:{logins_username},密码是:{logins_password}")
执行结果如下:
注意:
测试用例数=2*2,共有4条,根据数据算