原创:George555 公众号: 测试江湖路
(扫码加公众号,看更多相关内容)
一、安装:
1、基础包安装:pip install pytest
2、引用:import pytest #pip安装后,会在python安装目录的\Lib\site-packages下安装pytest.py文件,这样在使用时直接import pytest就行了
二、案例引入,先看个示例:
"""文件名:test_001.py"""
def fun(a):
return a+1
def test_001():
assert fun(2)==3
def test_002():
assert fun(2)==4
运行:在cmd命令框中输入:pytest test_001.py
执行结果:1个成功,1个失败
说明:测试文件后边的字母代表含义汇总:
“.” 代表测试通过,
F(Fail):失败
E(error):错误
s(skip):跳过
X(xpass):预期失败但是成功x,
xfail:预期失败执行也失败了.
三、理论部分
1、文件、包、类、函数编写规则:
文件或(包):必须以test_开头 或以_test结尾
类:必须以Test开头,且不含init方法
函数/方法:必须以test_开头
2.断言方法:assert
assert aa :判断aa为真
assert not aa :判断aa不为真
assert a in b :判断b包含a
assert a == b :判断a等于b
assert a != b :判断a不等于b
另外:如果断言后有错误的,想给出友好提示可以用下面方式:
assert 5 == add(4,4),"add()方法结果不等于5,而等于{0}".format(add(4,4))
3.相关使用
3.1 重复执行失败用例:pip install pytest-rerunfailures
使用示例:pytest test.py --reruns 3
3.2 测试报告: pip install pytest-html
使用示例:pytest test.py --html=./testreport.html
执行后生成如下报告:
3.3 顺序随机测试:pip install pytest-randomly
3.4 分布式并发测试用例集:
pip install pytest-xdist 或 pip install pytest-parallel
备注:pytest-parallel支持python3.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个线程运行。
3.5 出错立即返回:pip install pytest-instafail
3.6 集成jenkins的junit报告: 不用安装pytest已经集成了
使用命令:pytest --junitxml=path
使用示例:
pytest test.py --reruns 3 --html=./testreport.html --junitxml=xmlreport.xml
此时则执行完用例后,在本地目录生成testreport.html的测试报告,和xmlreport.xml的junit格式报告在jenkins中可调用展示。
3.7 参数化:
A.fixture中无参数,使用示例:
@pytest.fixture()
代码示例:
import pytest
def fun():
return "hello world"
@pytest.fixture() #添加fixture后,执行inty方法就是执行fun()方法
def inty():
return "connect to "+fun()
class TestCase():
#inty参数名必须同fixture的inty方法名相同才能传递inty的值
def test_open_baidu(self, inty):
print("============{}".format(inty))
执行后部分测试报告如下:
B.fixture中带有参数,使用示例:
@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))
执行后测试报告如下: 报告中用例都执行了2次,使用了params中的两个测试数据
备注:根据这样的例子,如果在测试中需要处理很多重复测试数据时,则这些数据就可以传入params里(可以另外写个方法读取txt/excel等文件测试数据值,以多字典列表形式返回所有测试数据),类似于unittest的DDT数据驱动方法。然后就会逐一去带入testcase里执行了
C.测试用例方法前直接加测试数据
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))
执行后测试报告如下:
D.测试用例方法前直接调用外部文件实现数据驱动
# -*- 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))
四、命令行运行
1.运行某个目录下全部用例
pytest -q ..\pytestAllure #运行当前文件所在目录的下所有case
即运行pytestAllure目录下所有test_*.py 或者*_test.py文件里的以Test开头的类(无__init__方法)下以test开头的方法
2.运行某py文件里的所有用例(即以Test开头的类下以test开头的方法)
pytest test_demo1.py
3.运行包含关键词的类或方法
pytest -k Test_pytestClass1 ..\pytestAllure
#执行pytestAllure目录下Test_pytestClass1 类下的所有test开头的case
pytest -k Test_pytestClass1 && case11 ..\pytestAllure
#执行pytestAllure目录下Test_pytestClass1 类下的所有case名包含case11的
4.用节点id来运行 用::来标识节点追踪方式
pytest test_demo1.py::Test_pytestClass1
#执行test_demo1.py文件中的Test_pytestClass1类下所有test开头的方法
执行后提示:
====1 failed, 1 passed, 1 warnings in 0.11 seconds ====
pytest test_demo1.py::Test_pytestClass1::test_case12
#执行test_demo1.py文件中的Test_pytestClass1类下的test_case12方法
执行后提示:
========== 1 failed, 1 warnings in 0.10 seconds ==========
5.怎么从包下运行所有用例
pytest --pyargs pkg.testing
这将导入pkg.testing并使用其文件系统位置来查找和运行测试。
6.怎么执行带@pytest.mark.errorcase的类或方法
pytest test_demo1.py -m errorcase #执行test_demo1.py文件中的标记为errorcase的test用例或类下全部test用例
代码:
@pytest.mark.errorcase
def test_case12(self):
assert 4==3,"两个数不相等"
执行后提示:
======1 failed, 1 deselected, 1 warnings in 0.10 seconds ======
7.怎么执行多个mark标记的类或方法
pytest test_demo1.py -m "case12 or case13"
#执行标记为case12和case13 的
pytest test_demo1.py -m "not case13" #不执行标记为case13的
代码:
def test_case11(self):
assert 3==3,"两个数相等"
@pytest.mark.case12
def test_case12(self):
assert 4==3,"两个数不相等"
@pytest.mark.case13
def test_case13(self):
assert 5==3,"两个数不相等"
执行后提示:
====== 2 failed, 1 deselected, 2 warnings in 0.12 seconds =====
8.怎么跳过指定类或方法
pytest test_demo1.py
代码如下:
@pytest.mark.skip #skip可以放在类前(跳过类),也可以放在方法前(跳过方法)
def test_case14(self):
assert 11==3,"两个数不相等"
执行后:
==== 0 failed, 0 passed, 1 skipped, 2 warnings in 0.11 seconds ====
9.怎么重复执行失败用例
pytest test_demo1.py --reruns 3 --reruns-delay 5
#重复执行失败用例,且每次执行器等待5秒后再继续
执行示例:
pytest ..\pytestAllure --reruns 3 --reruns-delay 4
执行后:
==== 4 failed, 2 passed, 1 skipped, 4 warnings, 12 rerun in 48.41 seconds =====
10.怎么生成html测试报告?
pytest ..\pytestAllure --html="testreport.html" #执行完pytestAllure下所有用例后,当前目录下生成testreport.html的测试报告
11.怎么生成jenkins集成后可用的junit测试报告文件
pytest test_demo1.py --junitxml=junitxml.xml
#执行后生成junit可用的xml报告文件
执行示例:
pytest ..\pytestAllure --reruns 3 --reruns-delay 4 --html="testreport.html" --junitxml="junitxmlreport.xml"
执行后:
--generated xml file: D:\workspace\pytestAllure\junitxmlreport.xml ---
--generated html file: file://D:\workspace\pytestAllure\testreport.html --
==4 failed, 2 passed, 1 skipped, 4 warnings, 12 rerun in 48.41 seconds ==
12.怎么使用python命令运行pytest
执行:python -m pytest testdemo.py
备注:使用python执行的,可以顺便把当前目录加入到sys.path中,即环境变量
13.pytest的退出码汇总
根据官方说法,提供了6种,分别如下:
Exit code 0: 所有用例执行成功后则返回0
Exit code 1: 所有用例执行后,有部分失败则返回1
Exit code 2: 测试执行时被用户中断
Exit code 3: 执行测试时发生内部错误
Exit code 4: pytest 命令行使用错误
Exit code 5: 没有收集到测试结果
备注:如果是要自定义退出码,则需要配合插件:pytest-custom_exit_code
14.运行用例遇到失败就停止
pytest -X testModu.py #遇到用例失败就停止,后面的不执行
pytest --maxfail=2 testModu.py #遇到第2个用例失败就停止,后面的不执行
###########一个比较全面的执行命令案例:#################
pytest -v test_demo1.py -k Test_pytestClass1 -m "case12 or case13" --reruns 3 --reruns-delay 3 --html=./report.html
以最详细的信息执行test_demo1.py文件中类名Test_pytestClass1 且用例名标记为case12或case13,如果有失败则重复运行3次且每次重复运行前等待3秒再继续,最后生成report.html报告
五、测试用例前置后置处理
# -*- coding:utf-8 -*-
'''
Created on 2019年8月6日
@author: George
前置、后置处理所有方法归纳如下:模块预处理:setup_module teardown_module
类预处理:setup_class teardown_class
函数预处理:setup_function teardown_function
方法预处理:setup_method teardown_method
用例预处理:setup teardown
备注:pytest包会识别这些方法名
文件名:test_demo7.py
'''
import pytest
def setup_module():
print("\n 这里是setup_module")
def teardown_module():
print("这里是teardown_module")
def setup_function():
print("这里是setup_function")
def teardown_function():
print("这里是teardown_function")
def test_case1():
print("这里是test_case1")
def test_case2():
print("这里是test_case2")
class Testclass():
def setup_class(self): #类似于unittest里的@classmethod
print("这里是setup_class")
def teardown_class(self):
print("这里是teardown_class")
def setup(self):
print("这里是setup")
def teardown(self):
print("这里是teardown")
def setup_method(self): #这里同setup方法作用其实一样
print("这里是setup_method")
def teardown_method(self):
print("这里是teardown_method")
def test_ClassCase1(self):
print("这里是test_testClassCase1")
def test_ClassCase2(self):
print("这里是test_testClassCase1")
if __name__=="__main__":
pytest.main(["-s", "test_demo7.py"])
#备注:-s:显示用例执行结果信息;-q :只显示结果,不显示过程
备注说明:
1.这几种方法全部使用优先级顺序如下:
setup_module->setup_function->setup_class->setup_method->setup->
teardown->teardown_method->teardown_class->teardown_function->teardown_module
2.其中setup_method/teardown_method 和setup/teardown 用在一起作用是一样的
3.setup_function/teardown_function是用在类以外,而setup_method/teardown_method 用在类之内
好了,pytest基本使用已经介绍完了,开始写测试脚本用例吧,后面会再更新一些高级使用(如:数据共享和数据作用域)
#####欢迎大家加群交流####
QQ:464314378
微信群请先加群主微信,群主会拉各位小伙伴进群,注意添加备注。
如果这些内容对你有帮助,也可以打开微信扫一扫,加关注: