最近很喜欢这么一句话:
你知道的越多,你不知道的越多。
上一次整理pytest的内容都是一年前了,发现越是深入地探究,越是有更多的内容值得探索。
先复习下之前整理的知识点,链接如下:
Pytest知识整合小记(一、pytest的运行)
Pytest知识整合小记(二、pytest用例的前置与后置、断言)
Pytest知识整合小记(三、参数化测试)
Pytest知识整合小记(四、fixture测试夹具)
Pytest知识整合小记(五、内置fixture)
Pytest知识整合小记(六、Allure结合禅道生成测试报告)
Pytest知识整合小记(七、pytest其他插件)
基于pytest+selenium+Allure的UI自动化测试框架搭建--詹崇伟
其中,在参数化测试这一块,讲到了使用@pytest.mark.parametrize这一块,最近在测试过程中,关于这一块的内容遇到了一点问题,便做个记录。
后来,仔细阅读了pytest.mark.parametrize的源码,发现是这么样子的:
翻译:
大致意思是:(英文不好,将就着看吧 - - !)
使用列进行参数化测试,如果要使用更复杂的测试方式,请参考indirect的设置方式。
第一个参数,argnames:用逗号分隔的字符串,表示一个或多个参数名称,或参数字符串的列表/元组。应该是类似"name1,name2,name3"
第二个参数,argvalues:大致意思是一个值对应的时候,可以这么设置[value1,value2],比如是这么样子,“name1”,[value1,value2],这样子的话就是有执行两个用例,但是当前面的argnames有多个的时候呢,格式就要变成这样子,“name1,name2”,[(value1,value2),(value3,value4)],就是说明中的,列表中用元组存储值。
第三个参数,indirect=False:,大致意思是这个设置只接收True或者False(默认是False)的布尔值,如果改成了True,那么argnames会被当成一个函数先执行,后面的argvalues就是这个函数的传参。
第四个参数,ids:即是所谓的用例编号,支持字符串或者可调用的列表作为输入。
第五个参数,scope:即指定作用域,目前还未用到。
OK,看了下源码里面对各项参数的说明,大体上有了个了解。所以大致上是这么用的:
用法1:
@pytest.mark.parametrize("a", [0, 1,2])
@pytest.mark.parametrize("b", [2, 3])
def test_1(a, b):
print("测试数据组合:a->%s, b->%s" % (a, b))
这么组合可以变成3*2共计6条测试用例的执行。
用法2:
或者是这么用:
@pytest.mark.parametrize("CarNumber,Type", [
pytest.param(BlackCarNumber,1,id='blacklist'),#黑名单
pytest.param(GreyCarNumber,2,id='greylist'),#灰名单
pytest.param(WhiteCarNumber,3,id='whitelist'),#白名单
]
)
给每个用例加上对应的用例编号。
现在用的比较多的方式,是数据与代码分离,数据部分用yaml、或者json、或者excel存储,通过读取的方式代入:
像这样:
pytest.mark.parametrize("a", exceldata)
@pytest.mark.parametrize("b", readyaml)
def test_1(a, b):
print("测试数据组合:a->%s, b->%s" % (a, b))
上面的内容在之前的文章第三节里面已经写过了,看对应的说明文档,后面还有一种用法没用过,就是对应的indirect的设置。
上面的说明里面提起过,不设置的话默认就是False,如果把他设置成True的话呢,会把前面的当成函数先执行。举个例:
import pytest
@pytest.fixturedef fixture_name(request):print("我执行了")return request.param
@pytest.mark.parametrize('fixture_name', ['zhan', 'chong'], indirect=True)def test_indirect(fixture_name):
assert fixture_name == 'zhan'
if __name__ == "__main__":
pytest.main(['-s','-v','testshuju.py'])
执行结果是这样的:
testshuju.py::test_indirect[zhan] 我执行了
PASSED
testshuju.py::test_indirect[chong] 我执行了
FAILED
如果是False呢,再试试,执行结果就是这样:
testshuju.py::test_indirect[zhan] PASSED
testshuju.py::test_indirect[chong] FAILED
看上面可以知道,如果设置为True,就是先把对应的函数执行了一遍,反之就没有。
那么换在自动化测试里面,这种设置可以起到什么作用呢?
我想了一下,应该是有几个便捷的点:
登录测试--像很多测试都要调用到登录,使用这一个装饰器就简单地一行代码解决了登录问题。
数据配置获取--数据配置部分,比如切换不同的配置要读取不同的数据等
特殊前置运行 --有些工能内容需要提前运行的,类似于登录。
遇到的坑:
之前在做接口或UI自动化测试的时候,遇到一些有数据依赖的内容,必须根据前文内容来执行后文工作的,用这种办法可以很舒服地解决不少问题。