unittest 和 pytest参数化对比:
pytest与unittest的一个重要区别就是参数化,unittest框架使用的第三方库ddt来参数化的
而pytest框架:
@pytest.mark.parametrize
来对测试用例进行传参Web UI自动化中的开发场景,比如是一个登录框:
1、需要测试账号空、密码空、账号密码都为空、账号不存在、密码错误、账号密码正确等情况
2、这些用例的区别就在于输入的测试数据和对应的交互结果
3、所以我们可以只写一条登录测试用例,然后把多组测试数据和期望结果参数化,节省很多代码量
@pytest.mark.parametrize(args_name,args_values,indirect=False, ids=None,scope=None)
@pytest.mark.parametrize()
装饰器接收两个参数,一个参数是以字符串的形式标识用例函数的参数,第二个参数以列表或元组的形式传递测试数据
import pytest
#待测试数据
def add(a,b):
return a+b
# 单个参数的情况
@pytest.mark.parametrize("a",[1,2,3,4])
def test_add(a): # 作为用例参数,接收装饰器传入的数据
print(" a的值:",a)
assert add(a,1) == a+1
执行结果
多个参数,@pytest.mark.parametrize()
第一个参数依然是字符串, 对应用例的多个参数,用逗号分隔,实际是一个解包的过程。
import pytest
def add(a,b):
return a+b
@pytest.mark.parametrize("a,b,c",[(1,2,3),(4,5,9),('1','2','12')])
def test_add(a,b,c):
print(f"\n a,b,c的值:{a},{b},{c}")
assert add(a,b)==c
执行结果
测试类的参数化,其实际上也是对类中的测试方法进行参数化。
当装饰器 @pytest.mark.parametrize
装饰测试类时,会将数据集合传递给类的所有测试用例方法
import pytest
data= [(1,2,3),(4,5,9)]
@pytest.mark.parametrize("a,b,c",data)
class TestStudy:
def test_parametrize_one(self,a,b,c):
print(f"\n 测试函数111 测试数据为 {a}-{b}")
assert a+b ==c
def test_parametrize_two(self, a, b, c):
print("\n 测试函数222 测试数据为 {}-{}".format(a,b))
assert a + b == c
执行结果
多个参数组合时使用的是笛卡尔积。
笛卡尔积:
# 笛卡尔积,组合数据
data_1=[1,2,3]
data_2=['a','b']
@pytest.mark.parametrize('a',data_1)
@pytest.mark.parametrize('b',data_2)
def test_parametrize_one(a,b):
print(f"笛卡尔积 测试数据为:{a},{b}")
执行结果
参数化,传入字典
# 字典
data_1=(
{
'user':1,
'pwd':2
},
{
'user':3,
'pwd':4
}
)
@pytest.mark.parametrize('dic',data_1)
def test_parametrize_1(dic):
print(f"测数据为 \n {dic}")
print(f"user:{dic['user']},pwd:{dic['pwd']}")
执行结果
参数化,标记数据
# 标记参数化
@pytest.mark.parametrize("test_input,expected",[
("3+5",8),
("2+4",6),
pytest.param("6 * 9",42,marks=pytest.mark.xfail),
pytest.param("6 * 6",42,marks=pytest.mark.skip)
])
def test_parametrize_mark(test_input,expected):
assert eval(test_input) == expected
执行结果
@pytest.mark.parametrize()
提供了 ids 参数来自定义显示结果,主要是为了更加清晰看到用例的含义
ids的长度需要与测试数据列表的长度一致,与fixture的ids参数是一样的,可参考fixture的ids。
# 增加可读性
data_1=[(1,2,3),(4,5,9)]
ids = ["a:{} + b:{} = expect:{}".format(a,b,expect) for a,b,expect in data_1]
@pytest.mark.parametrize("a,b,expect",data_1,ids=ids)
class TestParametrize(object):
def test_parametrize_1(self,a,b,expect):
print(f"测试函数1测试数据为 {a}--{b}")
assert a + b ==expect
def test_parametrize_2(self,a,b,expect):
print("测试函数2测试数据为 {}--{}".format(a,b))
assert a + b == expect
执行结果
fixture自身的params参数可以结合request来传参,详见fixture的其他参数介绍章节,当然也可以用parametrize来参数化代替params
indirect=True参数,目的是把传入的data当做函数去执行,而不是参数
如果测试方法写在类中,则 @pytest.mark.parametrize
的参数名称要与 @pytest.fixture
函数名称保持一致
应用场景:
@pytest.fixture()
def test_demo(request):
name = request.param
yield name
print(f"==测试数据是:{name}==")
data=["ceshi","qianduan"]
ids=[f"test_name is:{name}" for name in data]
@pytest.mark.parametrize("test_demo",data,ids=ids,indirect=True)
def test_name(test_demo):
print(f"测试用例的数据是:{test_demo}")
执行结果
知识点:
@pytest.fixture()
def logins(request):
param = request.param
yield param
print(f"账号是:{param['username']},密码是:{param['pwd']}")
data =[
{"username":"张三","pwd":"123456"},
{"username":"李四","pwd":"12345"}
]
@pytest.mark.parametrize("logins",data,indirect=True)
def test_name_pwd(logins):
print(f"账号是:{logins['username']},密码是:{logins['pwd']}")
执行结果
如果需要传多个参数,需要通过字典去传
# 多个fixture
@pytest.fixture()
def login_user(request):
user = request.param
yield user
print("账号:%s" % user)
@pytest.fixture()
def login_pwd(request):
pwd = request.param
yield pwd
print("密码:%s" % pwd)
data =[
{"username":"张三","pwd":"123456"},
{"username":"李四","pwd":"12345"}
]
@pytest.mark.parametrize("login_user,login_pwd",data,indirect=True)
def test_more_fixture(login_user,login_pwd):
print("fixture返回的内容:",login_user,login_pwd)
执行结果
@pytest.fixture(scope="function")
def login_user(request):
user = request.param
yield user
print("账号:%s" % user)
@pytest.fixture(scope="function")
def login_pwd(request):
pwd = request.param
yield pwd
print("密码:%s" % pwd)
name= ["张三","李四"]
pwd = ["123456","12345"]
@pytest.mark.parametrize("login_user",name,indirect=True)
@pytest.mark.parametrize("login_pwd",pwd,indirect=True)
def test_more_fixture(login_user,login_pwd):
print("fixture返回的内容:",login_user,login_pwd)
执行结果
[参考文章] 小菠萝测试笔记