1、pytest之不只是测试函数test_app能参数化,初始化函数before_test也能参数化
重点:测试用例的参数化+初始化清除函数的参数化 初始化清除函数的参数化能够实现appium的多终端测试
初始化清除函数的参数化,方法很多种:
before_test初始化函数注入参数,因为print(f’连接appium服务{port}')里面port需要变化的。
@pytest.fixture(scope=‘module’,params=[(4723,),(4727,)]):初始化清除函数的参数化
始化函数装饰器里面加params参数传参,port=request.param[0] 来调用params里的参数
#初始化清除函数的参数化:只传单个参数 import pytest
@pytest.fixture(scope='module',params=[(4723,),(4727,)]) #初始化清除函数的参数化params
def before_test(request):
port=request.param[0] #param[0],假如注入多个参数一个port和一个data--需要params传元组,
#params=[(4723,100),(4727,200)],一个参数的话不需要写成列表嵌套元素, #params[0]代表获取元组第一个
print("启动被测app")
print(f'连接appium服务{port}')
yield #后面写清除动作,
after_test()
#request是pytest的对象,我们在用对象里面的方法的时候pycham不会自动帮我们取显示名字, #它也不知道request里面到底什么内容
def after_test():
print('关闭被测app')
print('断开appium服务')
@pytest.mark.usefixtures('before_test')
@pytest.mark.parametrize('psw',['boss123','boss456'])
def test_app(psw):
print('测试boss app')
print(f'登录测试账号{psw}')
if __name__ == '__main__':
pytest.main(['pytest_ywt.py','-s'])
#初始化清除函数的参数化:传多个参数 import pytest
@pytest.fixture(scope='module',params=[(4723,'xiaomi'),(4727,'meizu')])
def before_testquest):
port=request.param[0] #param[0],假如注入多个参数一个port和一个data,需要params传元组,params=[(4723,100),(4727,200)],
#一个参数的话不需要写成列表嵌套元素,request.params[0]代表获取元组第一个
device=request.param[1] #request.param[1]对应元素里面第二个参数,
print(f"在{device}启动被测app")
print(f'连接appium服务{port}')
yield #后面写清除动作,
after_test()
#request是pytest的对象,(固定写法:request.param) #我们在用对象里面的方法的时候pycham不会自动帮我们去显示名字,它也不知道request里面到底什么内容
def after_test():
print('关闭被测app')
print('断开appium服务')
@pytest.mark.usefixtures('before_test')
@pytest.mark.parametrize('psw',['boss123','boss456'])
def test_app(psw):
print('测试boss app')
print(f'登录测试账号{psw}')
if __name__ == '__main__':
pytest.main(['pytest_ywt.py','-s'])
2、pytest框架执行代码也能在cmd里面直接输入命令执行
xxx\test_case> pytest -s
在test_case这个目录执行会运行test_case文件里面所有的测试文件(test开头的测试用例)
3、分布式
设置用例每个模块独立,有什么前置做到模块里面,比如测试10个模块,用相关联来做,不能做分布式(并发执行)
每个模块独立还能定制执行那个模块,关联性太强做不到;
最好做到每个接口都独立化(前置条件做好)不要做太大关联性的接口;
每一层都能做环境清除和定制化(包,模块。类,函数)分层,为后面mark(定点执行哪些用例)和分布式打基础。
分布式:必须做到用例的隔离(低耦合,高内聚),用例走串行风险很大,很难维护
3000个请求,全部独立化,然后分布式来做(效率提高几倍–几十倍)
4、分布式的实现
分布式的核心点:封装设计:相互独立,登录和课程相互独立,至少模块为单元要相互独立,封装相互独立,接口用例之间最好也相互独立 才能进行分布式
一:pytest分布式环境搭建和理论介绍:
第一步:安装一个库pip install pytest-xdist
分布式运行插件,可以做分布式(这个库有两种运行方式)
运行方式:
串行:顺序运行,串行运行,从头到尾
并行:pytest-xdist做分布式有两种,一种多核,一种多台机器
多核:单机多核来做(同时跑)使用-n参数
电脑多核有假有真:超线程技术(8内核搞成16核),真8核假8核—
cpu个数:硬件,几个cpu槽,i9900.i710–一般电脑就算一个cpu,单cpu,服务器可能有多个cpu
核数:电脑的核数。
逻辑核数:逻辑核数可以虚拟化,8核可以变成16核(超线程技术)
多核的话xdist本身的多核的话一般用逻辑核数来做的
多机(可以使用虚拟机)—需要搭环境,多台机器 很麻烦,装环境,下库
测试用例比较多怎么办:
分布式两种情况
量大:多机 (需要文件报告收集还需要搭环境,做起来比较麻烦)
单机多核,很简单,加-n 参数就行 (做ui和需要一些时间等待的时候时间优化特别明显)
串行运行:本身是线程去跑的,python就一个进程,里面很多线程,走进程的话需要多台机器来做,分量, 用例设计不好会有大问题,数据不对(用例一定要独立化)
并行和多机:用例一定要设计好,不然数据容易出错,逻辑独立(不能有任何关联,不能有前后关系) 数据和代码封装时候独立化
分布式运行代码
#验证单机多核分布式
import pytest
import time
def test_01():
time.sleep(3)
print("-----test01-----")
def test_02():
time.sleep(3)
print("-----test01-----")
if __name__ == '__main__':
# pytest.main(["test_xdist.py","-sq"]) #这是串行跑的 6s
pytest.main(["test_xdist.py", "-sq","-n","8"]) #单机多核并行 加"-n","8" 参数 ,用8个核来跑,5.41s,时间少了
#或者测试用例文件目录下 cmd,输入 pytest test_xdist.py -n 8 也可以 这样cmd里执行看到的结果更直观,
#多核来跑在ui里面时间提升很大,ui里面很多地方需要sleep,等待元素(有等待的的提升比较大)多核跑更快
#有等待的情况用多核跑效果越明显
串行运行本身按照线程去跑的,python本身就一个进程,里面很多线程
走进程的话,多台机器做比较合适—分量。
用例一定要设计好,不然数据容易出错,逻辑独立(不能有任何关联,不能有前后关系)----数据和代码封装时候独立化
pytest cmd执行多个模块用例:pytest test_xdist.py test_login.py -sq 运行两个.py文件(写多个运行多个)
pytest cmd执行多个包的用例:pytest test_xdist test_login -sq :运行test_xdist包和test_login 包
还可以运行不同模块的两个包,加包路径 case/test_xdist.py case2/test2_xdist.py
5、pytest的用例定制化执行mark标签
所有的接口不需要全部都跑(冒烟,定制化执行某些指定的业务,)“-m”,“test_lesson_add”
pytest框架mark标签,标记非常丰富,mark标签
mark标签:对于pytest,我们可以再每一个模块,每一个类,每一个方法和用例前面都加上mark,那样我们在pytest运行的时候就可以只运行带有该mark标签的模块,类,用例
这样的话可以方便我们选择执行自动化时,是执行全部用例,某个模块用例,某个流程用例,某个单独用例,总之就是可以某个单独的标签下所有用例
mark可以标记不同层次的东西(类,函数,方法都可以标记)文件不用标记(本身就可以定制化执行)
@pytest.mark.lessson_moudle 给测试类贴个标签,标签名字叫lessson_moudle标识课程模块,各个函数,类都可以贴上标签(类似别称),选择某个标签就运行某一个(灵活方便)
什么都不选中照常运行,(全部运行,没有限制)
mark标签pytest运行可能报错,PytestUnknownMarkWarning报错:是一个标签的mark警告,整个pytest这么写不识别你,但是不会报错,只是警告。
消除警告(增加标签栏,相当于标签的声明)
标签声明写法:teach_sq文件夹里创建一个pytest.ini的文件(pycham需要安装ini插件 file-setting-plugins(搜索ini)社区版似乎不行)
pycham找不到可以离线装
teach_sq
pytest.ini-----文件内容如下,相当于pytest的mark标签声明一下 #文件内容,markers后面把标签全部写上, lessson_moudle 一个类级别的mark标签名, #test_lesson_add,test_lesson_list,test_lesson_delete 三个函数级别的mark标签名称 # mark标签名称: 描述 这样的格式来写,前面声明标签名称,后面是描述(随便写)
[pytest]
markers=
lessson_moudle: teach_lesson # (标签名: 描述 这样的格式前面lesson_modle和test_lesson_add等是mark的标签名称,声明一个标签:冒号后面一定要加空格,规范)
后面的描述不建议写中文,会报错(需要转码,但是这个文件python自己调用的)
test_lesson_add: teach_lesson
test_lesson_list: teach_lesson
test_lesson_delete: teach_lesson
定制化执行test_lesson_add一个接口: “-m”,“test_lesson_add”
pytest.main([“test_lesson01.py”,“-s”,“-m”,“test_lesson_add”]) ---- -m就可以实现,mark定制化执行
定制化执行多个接口–逻辑或就行:“-m”,“test_lesson_add or test_lesson_delete”
pytest.main([“test_lesson01.py”,“-s”,“-m”,“test_lesson_add or test_lesson_delete”])
排除法排除一个-定制化除了某个接口不运行其他都运行—“-m”,“not test_lesson_add”
pytest.main([“test_lesson01.py”,“-s”,“-m”,“not test_lesson_add”])----除了test_lesson_add这个接口其他都运行
排除法排除多个-“-m”,“not (test_lesson_add or test_lesson_delete)”
pytest.main([“test_lesson01.py”,“-s”,“-m”,“not (test_lesson_add or test_lesson_delete)”])
筛选测试用例代码:
import pytest
@pytest.mark.zzzzz
def test_001():
print('test_001')
def test_002():
print('test_001')
if __name__ == '__main__':
pytest.main(["test1.py",'-s','-m','zzzzz'])
定制化执行:(组装流程)
mark标签:组装流程方便
-k:匹配筛选用例名称(可标准(全名)可模糊匹配)—指的是模块,-k和-m类似,有or和not。
但是-k只运行所有的用例,然后有排除模式,选定模式,还要其他模式(-k在cmd里面写的)
pytest -k test_lesson01.py :执行test_lesson01.py模块的测试用例(sq可以不写,只是不加打印,sq错误执行的时候会有很多信息可以打印,)
全部选中,测试包里面的模块全部被选中:pytest -k test,(差不多功能的模块写同样单词命名,这样-k可以一起匹配上)
lesson_1.py 和lesson_2.py:想运行两个文件 pytest -k lesson (默认模糊匹配lesson)
-m: 选择对应的标签(标签,mark需要打标签才能定制化执行,其他两个k和v不用打标签)
-v:节点,你要运行里面的某一个某一个里面的东西:(节点指定某一个)
示例:
pytest_lesson.py::Test_lesson::test_01
pytest -v pytest_lesson.py::Test_lesson::test_01
-sq:(简化print打印信息)
-s:输出print打印
-q:简化输出
sq,错误时候显示错误信息,或者fail很多失败信息,很多打印的时候写sq打印(成功不用写)
跳过/条件跳过:通过上下条件判断这个东西要不要跑,(两种)skip
跳过(没有条件的跳过,指定跳过,不需要满足什么条件)skip
@pytest.mark.skip("跳过test_lesson_add") #无条件跳过
接口函数前面写@pytest.mark.skip(“跳过test_lesson_add”),
这个接口就会被无条件跳过,不执行(报告里面会描述出来)
有条件的跳过skip if
@pytest.mark.skipif(1==1,reason="条件需要前面完成某一个步骤--前面条件为真的时候则跳过函数,不为真执行函数") #有条件的跳过
流程化需要跳过接口,1,2,3,
1为真运行的时候才执行2,1不执行2也不执行,直接跳过)
条件从哪里来,预期和实际的做个判断(找个前置条件做个判断是不是为真)
如果登录失败那么课程接口就不要取跑了(可以这么写)登录失败没有sessionid
使用场景:前面一个动作失败了后面的不要跑了。
前置条件,或者检测到服务器python环境不是要求的,不要跑。
对版本有要求(系统环境,解释器版本都可以作为代码要不要执行的前置条件)
标签只能到接口(方法层),不能指定到用例,用例是通过数据驱动来做的
定制执行还有一种写法:
指名道姓----(下面的指令可以在cmd控制台命令里面直接执行)
只执行Test1的测试用例,执行命令:pytest -sq test_xt.py::Test1
py文件到类,类级别的(::级别关系)
只想执行Test2中test_3,执行命令:pytest -sq test_xt.py::Test2::test_3
py文件,类,接口方法
同时执行多个条件:执行命令:pytest -sq test_xt.py::Test1::test01 test_xt.py::Test2::test02
也可以根据用例名称进行筛选-k,执行命令:pytest -sq -k 2 test_xt.py
下面是我整理的2023年最全的软件测试工程师学习知识架构体系图 |
永不止步,迎接挑战;心怀勇气,超越极限。勤奋与智慧铸就辉煌,激情与拼搏点亮未来。相信自己的能力与潜力,跨越困难,迈向成功的彼岸。
勇往直前,不畏艰辛;心怀信念,追逐梦想。奋斗的力量源于坚持与努力,每一次付出都将绽放成果的芬芳。相信自己的无限可能,拥抱挑战,创造属于自己的辉煌人生。不忘初心,砥砺前行,成功必将伴随着你!
无论遇到多少困难,坚持信念,不屈不挠。相信自己的能力与潜力,用汗水浇灌梦想的花朵。每一份努力都将累积力量,每一次奋斗都将迈向更高的巅峰。