一、pytest测试框架
特点:
1、非常容易上手,入门简单,文档丰富,文档中有很多参考实例
2、支持简单的单元测试和复杂的功能测试
3、支持参数化
4、执行测试用例过程中,支持跳过操作
5、支持重复执行失败的case
6、支持运行由Nose,unittest编写的测试case
7、pytest支持很多第三方插件
8、方便的和持续集成工具集成
1、pytest介绍及安装
-
pytest安装
-
在线安装 pip install pytest
-
离线安装方式 下载pytest离线安装包,并解压,然后在DOS下进入到解压的目录,然后执行 python setup.py install
-
pycharm
-
-
判断是否安装成功:
-
pip show pytest
-
pycharm
-
2、pytest类定义及方法定义及运行
-
pytest测试类的定义:类名必须是以Test开头
-
pytest测试方法的定义:方法名必须是以test开头
-
执行:在pycharm中右击方法名或者类名可以直接执行对应测试类或者测试方法
第二种运行方式: 通过pytest -s -v 测试文件名称 (-s 输出的用例输出的信息, -v输出的是执行的用例的类名以及方法名)
import pytest
def add(x, y):
return x+y
class TestADD: # 定义的类名必须是以Test开头
def test_add_01(self): # 定义的测试方法必须是以test开头
result = add(1, 2)
print(result)
def test_add_02(self):
result = add(2, 2)
print(result)
3、pytest 断言
-
pytest里面的断言方法就只有一个
assert 表达式
class TestADD: # 定义的类名必须是以Test开头 def test_add_01(self): # 定义的测试方法必须是以test开头 result = add(1, 2) print(result) # assert result == 3 # 判断相等 # assert result != 4 # 判断不相等 # assert result # 判断为True # assert False # 判断为False # assert "a" in "abc" # 判断包含 # assert "a" not in "abc" # 判断不包含 # assert result is None # assert result is not None
4、pytest 方法级别的fixture
-
pytest方法级别的fixture是针对每个测试方法,在执行测试方法前会执行fixture初始化的操作,在执行完测试方法后,执行fixture销毁的操作。
初始化的操作方法: def setup(self): 方法来实现。
销毁的操作方法: def teardown(self): 方法来实现。
import time def add(x, y): return x+y class TestAdd: def setup(self): print("测试用例开始执行时间:", time.strftime("%Y-%m-%D %H:%M:%S")) def test_add_01(self): result = add(1, 2) assert result == 3 def test_add_02(self): result = add(2, 2) assert result == 4 def teardown(self): print("测试用例结束时间:", time.strftime("%Y-%m-%d %H:%M:%S"))
5、pytest类级别的fixture
-
pytest 类级别的fixture针对每个测试类的初始化和销毁的操作,可以放在以下两个方法中
-
类级别初始化的方法: def setup_class(self):
-
类级别销毁的方法: def teardown_class(slef):
方法名称固定,不能修改。
-
import time
def add(x, y):
return x+y
class TestAdd:
# 添加类级别的初始化操作方法
def setup_class(self):
print("测试类开始执行时间:", time.strftime("%Y-%m-%d %H:%M:%S"))
# 添加类级别的销毁操作方法
def teardown_class(self):
print("测试类结束执行时间:", time.strftime("%Y-%m-%d %H:%M:%S"))
def setup(self):
print("测试方法开始执行时间:", time.strftime("%Y-%m-%d %H:%M:%S"))
def teardown(self):
print("测试方法结束时间:", time.strftime("%Y-%m-%d %H:%M:%S"))
def test_add_01(self):
result = add(1, 2)
print(result)
assert result == 3
def test_add_02(self):
result = add(2, 2)
print(result)
assert result == 4
fixture的方法必须写在测试类当中,不能写在测试类外面。
6、pytest配置文件
pytest的配置文件有固定的三个名称: pytest.ini tox.ini setup.cfg 这三个配置文件是放在项目的根目录下。
[pytest] # 标识当前配置文件是pytest的配置文件
addopts = -s -v # 标识pytest执行时增加的参数
testpaths = ./scripts # 匹配搜索的目录
python_files = test_*.py # 匹配测试文件
python_classes = Test* # 匹配测试类
python_functions = test_* # 匹配测试方法
Pytest插件
pytest测试报告
-
安装pytest测试报告插件
-
在线安装
-
离线安装
-
pycharm
-
-
使用方法
[pytest] addopts = -s -v --html=report/report.html testpaths = ./scripts python_files = test_*.py python_classes = Test* python_functions = test_*
一、pytest常用插件
2、控制用例执行顺序
-
unittest测试用例执行顺序是根据测试方法名称的assicc码值的大小来的,值越小排在前面(a-z)
-
pytest 正常情况下是根据测试方法的从上到下的顺序来执行
可以通过 pytest-ordering 插件来控制pytest测试方法执行的顺序。
-
安装:
-
在线安装: pip install pytest-ordering
-
离线安装: 下载对应的离线安装包,解压后,并进入到对应的目录,执行 python setup.py install
-
pycharm
-
-
使用
@pytest.mark.run(order=x) # x 表示的是整数,(既可以是负数也可以是正数)
-
全为负数或者正数时,值越小,优先级越高
-
既有正数,又有负数,那么正数优先级高
-
没有确定执行顺序的用例优先于负数
-
@pytest.mark.last # 设置用例最后执行
-
3、失败重试
-
pytest-rerunfailures 安装
-
在线安装
-
离线安装
-
pycharm
-
-
使用
在addopts参数行中增加对应的参数项: --reruns 3
当重复执行成功时,就不会再重复执行。
二、 pytest高级用法
1、跳过
@pytest.mark.skipif(condition, reason=None)
condition 表示是跳过的条件
这里面reason参数名称必填。
@pytest.mark.skip(reason=None)
reason表示的是跳过的原因
可以在测试类和测试方法上使用
import pytest
def add(x, y):
return x+y
version = 21
class TestAdd:
# @pytest.mark.last # 设置用例最后执行
def test_add_01(self):
result = add(1, 2)
assert 3 == result
@pytest.mark.skipif(version > 20, reason="大于2.0的版本不需要再执行此用例")
# @pytest.mark.skip("版本已更新,不需要再进行测试")
@pytest.mark.run(order=0)
def test_add_02(self):
result = add(2, 2)
assert 4 == result
@pytest.mark.run(order=-2)
def test_add_03(self):
result = add(3, 2)
assert 5 == result
2、数据的参数化
-
pytest参数化实现: @pytest.mark.parameterize(argnames, argvalues)
-
argnames 表示是 参数名字,是一串字符, 多个参数之间由逗号隔开 "username, password"
-
argvalues 表示的是参数化的数据 [("13700001111","123124"),("13800011111","123456")]
argname的参数个数要与argvalues里面的测试数据的个数要相同,否则会报错。
-
import pytest
def add(x, y):
return x+y
class TestAdd:
@pytest.mark.parametrize("x,y,expect", [(1, 2, 3), (2, 2, 4), (3, 2, 5)])
def test_add_01(self, x, y, expect):
result = add(x, y)
assert expect == result
读取yaml文件
-
name: 100元优惠券
money: 100
condition: 1000
createnum: 20
type: 1
send_start_time: 2022-06-26 20:01:08
send_end_time: 2022-07-26 20:01:08
use_start_time: 2022-06-27 20:01:08
use_end_time: 2022-08-26 20:01:08
use_type: 0
cat_id1: 0
cat_id2: 0
cat_id3: 0
status: 1
-
name: 2元优惠券
money: 200
condition: 1000
createnum: 20
type: 1
send_start_time: 2022-06-26 20:01:08
send_end_time: 2022-07-26 20:01:08
use_start_time: 2022-06-27 20:01:08
use_end_time: 2022-08-26 20:01:08
use_type: 0
cat_id1: 0
cat_id2: 0
cat_id3: 0
status: 1
import yaml
from parameterized import parameterized
import requests
def read_yaml():
with open(r"D:\dcs\dcs12\优惠券参数化\data\get_token.yaml", encoding="utf-8", mode="r") as f:
value = yaml.load(stream=f,Loader=yaml.FullLoader)
return value
a = read_yaml()
print(a)
url = {}
# a = [{'name': '100元优惠券', 'money': 100, 'condition': 1000, 'createnum': 20, 'type': 1, 'send_start_time': datetime.datetime(2022, 6, 26, 20, 1, 8), 'send_end_time': datetime.datetime(2022, 7, 26, 20, 1, 8), 'use_start_time': datetime.datetime(2022, 6, 27, 20, 1, 8), 'use_end_time': datetime.datetime(2022, 8, 26, 20, 1, 8), 'use_type': 0, 'cat_id1': 0, 'cat_id2': 0, 'cat_id3': 0, 'status': 1},
# {'name': '2元优惠券', 'money': 200, 'condition': 1000, 'createnum': 20, 'type': 1, 'send_start_time': datetime.datetime(2022, 6, 26, 20, 1, 8), 'send_end_time': datetime.datetime(2022, 7, 26, 20, 1, 8), 'use_start_time': datetime.datetime(2022, 6, 27, 20, 1, 8), 'use_end_time': datetime.datetime(2022, 8, 26, 20, 1, 8), 'use_type': 0, 'cat_id1': 0, 'cat_id2': 0, 'cat_id3': 0, 'status': 1}]
#
# data1 = a[0]
# data2 = a[1]
#
# requests.post(url=url,data=data1)
#
# requests.post(url=url,data=data2)
#
mok接口
import json
from flask import Flask,request
# 创建一个应用对象
app = Flask(__name__)
# 定义视图函数,设置路由规则
@app.route("/index")
def index():
print("访问的index主页")
return "hello mock"
# {"username":"admin", "password":"123456"}
@app.route("/api/sys/login",methods=["POST"])
def login():
result = json.loads(request.get_data().decode("utf-8")) # 字典形式的请求体数据
username = result.get("username")
password = result.get("password")
print(username,password)
if username =="13800000002" and password == "123456":
data = {
"success": True, "code": 10000,
"message":"操作成功!",
"token": "ajsdfj-12312-szs-fd-dfs"
}
else:
data = {
"success": False, "code": 99999,
"message": "抱歉,系统繁忙,请稍后重试",
"token": None
}
return data
if __name__ == '__main__':
# 启动WEB服务器
app.run()