python有很多不错的测试框架,比如RobotFramework,Unitest,这里要介绍一下pytest。可以参考,pytest文档
因为文档介绍比较多,这里使用简单的几篇帖子引导快速入门并灵活使用。
通过安装和一个简单的实例先入为主,体验一下如何使用。
pip3 install pytest
安装之后在在python37libsite-packages目录下安装对应的pytest包,使用的时候直接引入import pytest即可。
2 用例"""文件名:test_001.py"""
def fun(inputNum)->int:
return inputNum+1
def test_001():
assert fun(2)==3
def test_002():
assert fun(2)==4
在命令行执行:pytest test_001.py
python脚本以test或者test命名后,执行对应的pytest 文件名.py即可执行
说明:测试文件后边的字母代表含义汇总:
- .:绿色表示执行通过
- F :Fali失败
- E:Error错误
- s:Skip跳过
- X:Xpass预期失败但是成功
- xfail:有切失败执行失败
pytest中,命名要求:
- 文件/包需要以test_开头或者_test结尾
- 类名必须以Test开头,且不含__init__方法
- 方法/或者函数,必须以test_开头
pytest中断言判断使用assert,主要有以下几种断言
assert flag # 断言flag为True assert not flag #断言flag为False assert subset in set #断言subset存在于set中 assert a == b #断言a等于b assert a != b #断言a和b不相等3.3 pytest使用命令 1.重试
有时候可能因为环境等问题导致用例执行失败,此时考虑到重复执行,此时可以使用命令
# 安装rerun包 pip install pytest-rerunfailures # 失败后重试3次 pytest test.py --reruns 32.测试报告
既然是介绍基本的知识,这里对于测试报告先使用html,如果深入了解后,可以使用allure展示测试报告,这里先介绍下html
pip install pytest-html pytest test_001.py --html=./testreport.html
python的执行是从上到下依次执行,有时候需要做一些混沌测试,这个时候最好是可以顺序随机执行测试用例。
pip install pytest-randomly
具体使用方法可参考pytest-randomly
4.并发执行python因为GIL的原因导致无法实现正在的多线程并发,因此可以根据其中的某些特性实现“并发请求”,从而减缓了大量请求的的sleep时间。主要有多线程(线程池),多进程,异步IO等。pytest中也有两种方式实现并发请求。
pip install pytest-xdist pip install pytest-parallel # python version > 3.6
如果需要做多进程的并发,只能使用linux系统或者是mac。如果是多线程可以在windows上
–workers (optional) * :多进程运行需要加此参数, *是进程数。默认为1。 –tests-per-worker (optional) * :多线程运行, *是每个worker运行的最大并发线程数。默认为1
pytest test.py --workers 3:3个进程运行 pytest test.py --tests-per-worker 4:4个线程运行 pytest test.py --workers 2 --tests-per-worker 4:2个进程并行,且每个进程最多4个线程运行,即总共最多8个线程运行。5.出错后操作
常稳测试用例或者批量跑测试用例的时候,一般不希望其中一个用例执行失败后就结束整个自动化的运行过程。但是有时候确实有些特殊情况,需要在一遇到失败就就理解终止运行。
pip install pytest-instafail6.集成报告
集成jenkins的junit报告: 不用安装pytest已经集成了
使用命令:pytest --junitxml=path
此时则执行完用例后,在本地目录生成testreport.html的测试报告,和xmlreport.xml的junit格式报告在jenkins中可调用展示。
7. 数据准备数据准备比如执行case前需要给某个case准备好传递的参数数据。介绍参数之前,先说说测试的基本过程,一般可以分为4个步骤
- Arrange 安排或者说布局,执行测试所需要的设置和初始化
- Act 采取测试所需的行动
- Assert 验证测试结果
- Cleanup 环境恢复
那pytest中的fixture几乎可以干了上面的124的工作。可参考fixture
import pytest
def fun():
return "hello world"
@pytest.fixture()
def inty():
return "connect to "+fun()
class TestCase():
#inty参数名必须同fixture的inty方法名相同才能传递inty的值
def test_open_baidu(self, inty):
print("============{}".format(inty))
**注意:**pytest.fixture()装饰器定义的对象名inty必须和方法调用的参数名inty一致
fixture有参最常用的场景是,测试登录,比如给一个账户和ID,或者账户和密码,需要遍历各种类型测试其正确性
@pytest.fixture(params=[
{key11:value1,key12:value2} ,
{key21:value21,key22:value22}
]
)
import pytest
@pytest.fixture(params=[{'userID':'00001','username':'jack'},
{'userID':'00002','username':'mike'}])
def getdata(request): #这里的request是固定参数名
#分别打印params的字典项:{'userID': '00001', 'username': 'jack'}
#和{'userID':'00002','username':'mike'}
print("request.param======",request.param)
return request.param #这里的request.param也是固定的
class TestCase():
def test_case1(self, getdata):
print("第1个用例输出:{}".format(getdata))
def test_case2(self, getdata):
print("第2个用例输出:{}".format(getdata))
**注意:**pytest.fixture(参数)传递参数时,在get属性中时,只能设置get方法的参数为request
这里可以看到每个用例执行了两次,第一次是执行第一个参数,第二次是验证第二个参数。
根据这样的例子,如果在测试中需要处理很多重复测试数据时,则这些数据就可以传入params里(可以另外写个方法读取txt/excel等文件测试数据值,以多字典列表形式返回所有测试数据),类似于unittest的DDT数据驱动方法。然后就会逐一去带入testcase里执行了
测试过程中,建一个一个.py文件验证一个场景,这样是最为方便的(比如方便维护,方便其他teamer审阅功能等),但是有时候需要在某些方法前给其加上独有的参数
import pytest
class TestCase():
@pytest.mark.parametrize("getdataA",
[{'userID':'00001','username':'jack'},
{'userID':'00002','username':'mike'}])
def test_case1(self, getdataA):
print("第1个用例输出:{}".format(getdataA))
@pytest.mark.parametrize("getdataB",
[{'userID':'00003','username':'tina'},
{'userID':'00004','username':'book'}])
def test_case2(self, getdataB):
print("第2个用例输出:{}".format(getdataB))
输出测试报告:
那结合上面fixture中有参数的场景和本节中给某个函数指定参数的场景
import pytest
@pytest.fixture(params=[{'userID':'00001','username':'jack'},
{'userID':'00002','username':'mike'}])
def getdata(request): #这里的request是固定参数名
#分别打印params的字典项:{'userID': '00001', 'username': 'jack'}
#和{'userID':'00002','username':'mike'}
print("request.param======",request.param)
return request.param #这里的request.param也是固定的
class TestCase():
def test_case1(self, getdata):
print("第1个用例输出:{}".format(getdata))
@pytest.mark.parametrize("getdataB",
[{'userID':'studenta','username':'tina'},
{'userID':'studentb','username':'book'}])
def test_case2(self, getdataB):
print("第2个用例输出:{}".format(getdataB))
输出测试报告:
既然在fixture有参章节中提到了使用外部数据作为入参进行传递,那么这里就跟着介绍一下
# -*- coding:utf-8 -*-
import pytest,csv
def getCsvContents(csvFileUrl):
'''把csv格式文件转换为字典列表方法'''
with open(csvFileUrl,'r') as csv_f:
reader = csv.reader(csv_f)
fieldnames = next(reader)
csv_reader = csv.DictReader(csv_f,fieldnames=fieldnames)
kwList=[]
for row in csv_reader:
d = {}
for k, v in row.items():
d[k] = v
kwList.append(d)
return kwList
class TestCase():
@pytest.mark.parametrize("getdataA",getCsvContents('test.txt'))
def test_case1(self, getdataA):
print("第1个用例输出:{}".format(getdataA))
@pytest.mark.parametrize("getdataB",getCsvContents('test.txt'))
def test_case2(self, getdataB):
print("第2个用例输出:{}".format(getdataB))



