前言
基于requests+pytest的接口测试框架,可以以上文的requests+unittest为基础进行扩展替换。将unittest和HtmlReport替换成功能更强大的pytest和Allure。
测试项目依旧是:likeshop商城
网址:http://101.43.8.10:6969/ (H5版)
1、登录接口:
2、商品详情接口:
3、添加到购物车接口:
4、生成订单接口:
5、订单详情接口:
单接口功能测试
框架的目录结构
组织测试框架,梳理文件结构目录如下:
- common:存放公共方法
- test_case:存放测试用例
- test_data:存放测试数据
- config:存放配置文件
- lib:存放第三方库文件
- logs:存放日志文件,每天一个日志文件
- report:存放生成测试报告的位置
- run.py:框架主入口文件
将前文Requests+UnitTest中的公共方法都迁移过来,比如common目录中的所有文件、config文件、test_data中excel文件等。两个框架最大的区别在于test_case的设计、执行及报告。
安装第三方库
$ pip install pytest
$ pip install requests
$ pip install pyyaml
$ pip install openpyxl
$ pip install jsonpath
$ pip install pytest-html
$ pip install pytest-rerunfailures
$ pip install pytest-xdist
$ pip install allure-pytest

登录功能测试用例
在test_case目录下方,新建test_login_01.py
import json
import os
import pytest
import allure
from common.excel_util import ExcelReader
from common.assert_util import pl_assert
from common.config_util import ConfigYaml
from common.path_util import get_data_path
from common.pl_requests import PLRequests
PLRequests = PLRequests()
conf_y = ConfigYaml()
@allure.feature("LikeShop商城_Login")
class Test_login:
reader = ExcelReader(get_data_path() + os.sep + conf_y.get_file_name('login'), conf_y.get_sheet_name('login'))
cases = reader.read_data()
@pytest.mark.parametrize("cases", cases)
def test_01_login(self, cases):
allure.dynamic.title(cases["测试用例ID"] + cases["接口名称"])
allure.dynamic.story(cases["模块"])
url = conf_y.get_host() + cases['请求URL']
data = json.loads(cases["请求数据"])
method = cases["请求方法"]
allure.dynamic.description(
"请求地址:" + url + "\n请求方法:" + method + "\n响应体提取器:" + str(cases["extract"]) + "\n预期结果断言表达式:" + cases["期望结果断言"])
response = PLRequests.pl_requests(method, url=url, data=data)
pl_assert(cases["期望结果断言"], response.json())
执行结果:
$ python run.py
========================================================================== test session starts ===========================================================================
platform darwin -- Python 3.9.12, pytest-7.2.1, pluggy-1.0.0 -- /Users/laobai/workspaces/testdemo_pytest/venv/bin/python
cachedir: .pytest_cache
metadata: {'Python': '3.9.12', 'Platform': 'macOS-10.14.6-x86_64-i386-64bit', 'Packages': {'pytest': '7.2.1', 'pluggy': '1.0.0'}, 'Plugins': {'html': '3.2.0', 'allure-pytest': '2.12.0', 'metadata': '2.0.4'}, 'JAVA_HOME': '/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home'}
rootdir: /Users/laobai/workspaces/testdemo_pytest, configfile: pytest.ini
plugins: html-3.2.0, allure-pytest-2.12.0, metadata-2.0.4
collected 1 item
test_case/test_login_01.py::Test_login::test_01_login[cases0] 2023-01-17 17:23:48,091 PLS自动化测试 INFO pl_requests.py [21] 请求方法:POST
2023-01-17 17:23:48,092 PLS自动化测试 INFO pl_requests.py [22] 请求url:http://101.43.8.10:6969/api/account/login
2023-01-17 17:23:48,092 PLS自动化测试 INFO pl_requests.py [23] 请求headers:None
2023-01-17 17:23:48,092 PLS自动化测试 INFO pl_requests.py [24] 请求参数(params):None
2023-01-17 17:23:48,092 PLS自动化测试 INFO pl_requests.py [25] 请求数据(data):{'account': '17900000001', 'password': 'a123456', 'client': '2'}
2023-01-17 17:23:48,092 PLS自动化测试 INFO pl_requests.py [26] 请求数据(json):None
2023-01-17 17:23:48,092 PLS自动化测试 INFO pl_requests.py [32] 发送post请求
2023-01-17 17:23:48,300 PLS自动化测试 INFO pl_requests.py [42] 响应结果:
{
"code": 1,
"msg": "登录成功",
"data": {
"id": 1,
"nickname": "测试账号一",
"avatar": "http://101.43.8.10:6969/static/common/image/default/user.png",
"level": 1,
"disable": 0,
"distribution_code": "TVHYKM",
"token": "06573a6f78f49070920594425be0a293"
},
"show": 0,
"time": "0.104002"
}
2023-01-17 17:23:48,301 PLS自动化测试 INFO assert_util.py [20] 从Excel中提取的断言字段:[{'expr': '$.msg', 'expected': '登录成功', 'type': 'eq'}, {'expr': '$.code', 'expe 'eq'}]
2023-01-17 17:23:48,301 PLS自动化测试 INFO assert_util.py [23] 要断言的内容为:{'expr': '$.msg', 'expected': '登录成功', 'type': 'eq'}
2023-01-17 17:23:48,302 PLS自动化测试 INFO assert_util.py [28] 从响应结果中提取到的值为:登录成功
2023-01-17 17:23:48,302 PLS自动化测试 INFO assert_util.py [29] 期望结果为:登录成功
2023-01-17 17:23:48,302 PLS自动化测试 INFO assert_util.py [32] 提取值与期望结果的断言结果为:True
2023-01-17 17:23:48,303 PLS自动化测试 INFO assert_util.py [23] 要断言的内容为:{'expr': '$.code', 'expected': '1', 'type': 'eq'}
2023-01-17 17:23:48,303 PLS自动化测试 INFO assert_util.py [28] 从响应结果中提取到的值为:1
2023-01-17 17:23:48,303 PLS自动化测试 INFO assert_util.py [29] 期望结果为:1
2023-01-17 17:23:48,303 PLS自动化测试 INFO assert_util.py [32] 提取值与期望结果的断言结果为:True
2023-01-17 17:23:48,303 PLS自动化测试 INFO assert_util.py [42] 断言成功!
PASSED
-------------------------------------------- generated html file: file:///Users/laobai/workspaces/testdemo_pytest/report.html --------------------------------------------
=========================================================================== 1 passed in 0.69s ============================================================================
Report successfully generated to /Users/laobai/workspaces/testdemo_pytest/report/html
多接口流程测试
下单流程测试用例
根据上方的单接口测试以及前文的unittest实例,迁移多接口测试的代码如下:
test_order_flow.py
import pytest
import json
import os
import allure
from common.pl_requests import PLRequests
from common.excel_util import ExcelReader
from common.path_util import get_data_path
from common.config_util import ConfigYaml
from common.assert_util import pl_assert
from common.extract_util import extract_data_from_response
from common.pl_util_plus import replace_case_with_re
from common.log_util import pl_log
PLRequests = PLRequests()
conf_y = ConfigYaml()
@allure.feature("LikeShop商城_下单流程")
class TestOrderFlow:
reader = ExcelReader(get_data_path() + os.sep + conf_y.get_file_name('order_flow'),
conf_y.get_sheet_name('order_flow'))
cases = reader.read_data()
@pytest.mark.parametrize("cases", cases)
def test_order_flow(self, cases):
new_cases = replace_case_with_re(cases)
allure.dynamic.story(new_cases["模块"])
allure.dynamic.title(new_cases["测试用例ID"] + new_cases["接口名称"])
headers = None
if new_cases['Headers'] is not None:
headers = json.loads(new_cases['Headers'])
url = conf_y.get_host() + str(new_cases['请求URL'])
if new_cases['请求数据类型'] == 'params':
params = json.loads(new_cases['请求数据'])
allure.dynamic.description(
"请求地址:" + url + "\n请求方法:" + cases["请求方法"] + "\n响应体提取器:" + str(cases["extract"]) + "\n预期结果断言表达式:" +
cases["期望结果断言"])
response = PLRequests.pl_request(new_cases["请求方法"], url=url, params=params, headers=headers)
elif new_cases['请求数据类型'] == 'data':
data = json.loads(new_cases['请求数据'])
allure.dynamic.description(
"请求地址:" + url + "\n请求方法:" + cases["请求方法"] + "\n响应体提取器:" + str(cases["extract"]) + "\n预期结果断言表达式:" +
cases["期望结果断言"])
response = PLRequests.pl_request(new_cases["请求方法"], url=url, data=data, headers=headers)
elif new_cases['请求数据类型'] == 'json':
json_str = new_cases['请求数据']
allure.dynamic.description(
"请求地址:" + url + "\n请求方法:" + cases["请求方法"] + "\n响应体提取器:" + str(cases["extract"]) + "\n预期结果断言表达式:" +
cases["期望结果断言"])
response = PLRequests.pl_request(new_cases["请求方法"], url=url, data=json_str, headers=headers)
else:
response = PLRequests.pl_request(new_cases["请求方法"], url=url)
pl_assert(new_cases["期望结果断言"], response.json())
# 在有extract列的请求的响应结果中提取数据,并设置为全局变量
if new_cases["extract"]:
extract_data_from_response(new_cases["extract"], response.json())
pl_log.info("从接口请求中获取全局变量提取表达式为:{}".format(new_cases["extract"]))
if new_cases["期望结果断言"]:
pl_assert(new_cases["期望结果断言"], response.json())
可以看到代码有大量冗余(request),需要进行抽象精简。下面将请求数据的判断抽象成方法
# 对请求数据进行数据整理
def data_cleaning(cases):
......
pl_log.info("excel中的数据经过整理后:\n{}".format(rest_data))
return rest_data
test_order_flow.py精简为:
import pytest
import json
import os
from common.pl_requests import PLRequests
from common.excel_util import ExcelReader
from common.path_util import get_data_path
from common.config_util import ConfigYaml
from common.assert_util import pl_assert
from common.extract_util import extract_data_from_response
from common.pl_util_plus import replace_case_with_re, data_cleaning
from common.log_util import pl_log
PLRequests = PLRequests()
conf_y = ConfigYaml()
class TestOrderFlow:
reader = ExcelReader(get_data_path() + os.sep + conf_y.get_file_name('order_flow'),
conf_y.get_sheet_name('order_flow'))
cases = reader.read_data()
@pytest.mark.parametrize("cases", cases)
def test_order_flow(self, cases):
# 从excel读取到的每一行数据,先进行变量替换,再进行整理
new_cases = data_cleaning(replace_case_with_re(cases))
response = PLRequests.pl_request(method=new_cases["请求方法"], url=new_cases["url"], headers=new_cases['Headers'],
params=new_cases['请求数据'], data=new_cases['请求数据'], json=new_cases["请求数据"])
pl_assert(new_cases["期望结果断言"], response.json())
# 在有extract列的请求的响应结果中提取数据,并设置为全局变量
if new_cases["extract"]:
extract_data_from_response(new_cases["extract"], response.json())
pl_log.info("从接口请求中获取全局变量提取表达式为:{}".format(new_cases["extract"]))
增加Allure装饰及描述
test_login_01.py
import json
import os
import pytest
import allure
from common.excel_util import ExcelReader
from common.assert_util import pl_assert
from common.config_util import ConfigYaml
from common.path_util import get_data_path
from common.pl_requests import PLRequests
PLRequests = PLRequests()
conf_y = ConfigYaml()
@allure.epic("LikeShop商城")
@allure.feature("功能测试")
class Test_login:
reader = ExcelReader(get_data_path() + os.sep + conf_y.get_file_name('login'), conf_y.get_sheet_name('login'))
cases = reader.read_data()
@pytest.mark.parametrize("cases", cases)
def test_01_login(self, cases):
allure.dynamic.title(cases["测试用例ID"] + cases["接口名称"])
allure.dynamic.story(cases["模块"])
url = conf_y.get_host() + cases['请求URL']
data = json.loads(cases["请求数据"])
method = cases["请求方法"]
allure.dynamic.description(
"请求地址:" + url + "\n请求方法:" + method + "\n响应体提取器:" + str(cases["extract"]) + "\n预期结果断言表达式:" + cases["期望结果断言"])
response = PLRequests.pl_request(method, url=url, data=data)
pl_assert(cases["期望结果断言"], response.json())
test_order_flow_01.py
import pytest
import os
import allure
from common.pl_requests import PLRequests
from common.excel_util import ExcelReader
from common.path_util import get_data_path
from common.config_util import ConfigYaml
from common.assert_util import pl_assert
from common.extract_util import extract_data_from_response
from common.pl_util_plus import replace_case_with_re, data_cleaning
from common.log_util import pl_log
PLRequests = PLRequests()
conf_y = ConfigYaml()
@allure.epic("LikeShop商城")
@allure.feature("流程测试")
class TestOrderFlow:
reader = ExcelReader(get_data_path() + os.sep + conf_y.get_file_name('order_flow'),
conf_y.get_sheet_name('order_flow'))
cases = reader.read_data()
@pytest.mark.parametrize("cases", cases)
def test_order_flow(self, cases):
# 从excel读取到的每一行数据,先进行变量替换,再进行整理
new_cases = data_cleaning(replace_case_with_re(cases))
allure.dynamic.story(new_cases["模块"])
allure.dynamic.title(new_cases["测试用例ID"] + "_" + new_cases["接口名称"])
allure.dynamic.description(
"请求地址:" + new_cases["url"] + "\n请求方法:" + cases["请求方法"] + "\n请求数据:" + cases["请求数据"] + "\n响应体提取器:" + str(
cases["extract"]) + "\n预期结果断言表达式:" +
cases["期望结果断言"])
response = PLRequests.pl_request(method=new_cases["请求方法"], url=new_cases["url"], headers=new_cases['Headers'],
params=new_cases['请求数据'], data=new_cases['请求数据'], json=new_cases["请求数据"])
pl_assert(new_cases["期望结果断言"], response.json())
# 在有extract列的请求的响应结果中提取数据,并设置为全局变量
if new_cases["extract"]:
extract_data_from_response(new_cases["extract"], response.json())
pl_log.info("从接口请求中获取全局变量提取表达式为:{}".format(new_cases["extract"]))
执行测试并生成报告
执行run.py
$ python run.py
=================================================================================================== test session starts ===================================================================================================
platform darwin -- Python 3.9.12, pytest-7.2.1, pluggy-1.0.0 -- /Users/laobai/workspaces/testdemo_pytest/venv/bin/python
cachedir: temp
metadata: {'Python': '3.9.12', 'Platform': 'macOS-10.14.6-x86_64-i386-64bit', 'Packages': {'pytest': '7.2.1', 'pluggy': '1.0.0'}, 'Plugins': {'html': '3.2.0', 'allure-pytest': '2.12.0', 'metadata': '2.0.4'}, 'JAVA_HOME': '/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home'}
rootdir: /Users/laobai/workspaces/testdemo_pytest, configfile: pytest.ini
plugins: html-3.2.0, allure-pytest-2.12.0, metadata-2.0.4
collected 11 items
test_case/test_login_01.py::Test_login::test_01_login[cases0] 2023-01-18 14:45:56,217 PLS自动化测试 INFO pl_requests.py [21] 请求方法:POST
2023-01-18 14:45:56,217 PLS自动化测试 INFO pl_requests.py [22] 请求url:http://101.43.8.10:6969/api/account/login
2023-01-18 14:45:56,217 PLS自动化测试 INFO pl_requests.py [23] 请求headers:None
2023-01-18 14:45:56,217 PLS自动化测试 INFO pl_requests.py [24] 请求参数(params):None
2023-01-18 14:45:56,217 PLS自动化测试 INFO pl_requests.py [25] 请求数据(data):{'account': '17900000001', 'password': 'a123456', 'client': '2'}
2023-01-18 14:45:56,218 PLS自动化测试 INFO pl_requests.py [26] 请求数据(json):None
2023-01-18 14:45:56,218 PLS自动化测试 INFO pl_requests.py [32] 发送post请求
2023-01-18 14:45:56,452 PLS自动化测试 INFO pl_requests.py [42] 响应结果:
{
"code": 1,
"msg": "登录成功",
"data": {
"id": 1,
"nickname": "测试账号一",
"avatar": "http://101.43.8.10:6969/static/common/image/default/user.png",
"level": 1,
"disable": 0,
"distribution_code": "TVHYKM",
"token": "f3b00122a7bb27b24c83f122ec04cf87"
},
"show": 0,
"time": "0.099399"
}
2023-01-18 14:45:56,453 PLS自动化测试 INFO assert_util.py [20] 从Excel中提取的断言字段:[{'expr': '$.msg', 'expected': '登录成功', 'type': 'eq'}, {'expr': '$.code', 'expected': '1', 'type': 'eq'}]
2023-01-18 14:45:56,453 PLS自动化测试 INFO assert_util.py [23] 要断言的内容为:{'expr': '$.msg', 'expected': '登录成功', 'type': 'eq'}
2023-01-18 14:45:56,454 PLS自动化测试 INFO assert_util.py [28] 从响应结果中提取到的值为:登录成功
2023-01-18 14:45:56,454 PLS自动化测试 INFO assert_util.py [29] 期望结果为:登录成功
2023-01-18 14:45:56,454 PLS自动化测试 INFO assert_util.py [32] 提取值与期望结果的断言结果为:True
2023-01-18 14:45:56,454 PLS自动化测试 INFO assert_util.py [23] 要断言的内容为:{'expr': '$.code', 'expected': '1', 'type': 'eq'}
2023-01-18 14:45:56,454 PLS自动化测试 INFO assert_util.py [28] 从响应结果中提取到的值为:1
2023-01-18 14:45:56,454 PLS自动化测试 INFO assert_util.py [29] 期望结果为:1
2023-01-18 14:45:56,454 PLS自动化测试 INFO assert_util.py [32] 提取值与期望结果的断言结果为:True
2023-01-18 14:45:56,454 PLS自动化测试 INFO assert_util.py [42] 断言成功!
PASSED
.......篇幅原因只截取部分日志......
test_case/test_order_flow01.py::TestOrderFlow::test_order_flow[cases4] 2023-01-18 14:45:57,807 PLS自动化测试 INFO pl_util_plus.py [40] 要替换的mark占位符有:['order_id', 'token']
2023-01-18 14:45:57,807 PLS自动化测试 INFO pl_util_plus.py [46] 将占位符order_id替换为47
2023-01-18 14:45:57,808 PLS自动化测试 INFO pl_util_plus.py [46] 将占位符token替换为7c10879cf4f37bcd49e6b60239ad2763
2023-01-18 14:45:57,808 PLS自动化测试 INFO pl_util_plus.py [50] 替换后的用例数据为:
{'测试用例ID': 'order_flow_05', '模块': '下单流程', '接口名称': '订单详情', '请求URL': 'order/detail', '前置条件': None, '请求方法': 'GET', '请求数据类型': 'params', '请求数据': '{"id": "47"}', 'Headers': '{"token": "7cokies': None, 'extract': None, '期望结果断言': '[{"expr": "$.msg", "expected": "获取成功", "type": "eq"}]', '是否运行': None, '状态码': None, '数据库验证': None, '备注': None}
2023-01-18 14:45:57,808 PLS自动化测试 INFO pl_util_plus.py [84] excel中的数据经过整理后:
{'Headers': {'token': '7c10879cf4f37bcd49e6b60239ad2763'}, '请求数据': {'id': '47'}, '模块': '下单流程', '测试用例ID': 'order_flow_05', '接口名称': '订单详情', 'url': 'http://101.43.8.10:6969/api/order/detail', '请求方法xpr": "$.msg", "expected": "获取成功", "type": "eq"}]', 'extract': None}
2023-01-18 14:45:57,808 PLS自动化测试 INFO pl_requests.py [21] 请求方法:GET
2023-01-18 14:45:57,808 PLS自动化测试 INFO pl_requests.py [22] 请求url:http://101.43.8.10:6969/api/order/detail
2023-01-18 14:45:57,808 PLS自动化测试 INFO pl_requests.py [23] 请求headers:{'token': '7c10879cf4f37bcd49e6b60239ad2763'}
2023-01-18 14:45:57,808 PLS自动化测试 INFO pl_requests.py [24] 请求参数(params):{'id': '47'}
2023-01-18 14:45:57,808 PLS自动化测试 INFO pl_requests.py [25] 请求数据(data):{'id': '47'}
2023-01-18 14:45:57,808 PLS自动化测试 INFO pl_requests.py [26] 请求数据(json):{'id': '47'}
2023-01-18 14:45:57,809 PLS自动化测试 INFO pl_requests.py [29] 发送get请求
2023-01-18 14:45:57,943 PLS自动化测试 INFO pl_requests.py [42] 响应结果:
{
"code": 1,
"msg": "获取成功",
"data": {
"id": 47,
"order_sn": "202301181445575928",
"order_type": 1,
"order_status": 1,
"pay_status": 1,
"pay_way": 3,
"pay_time": "2023-01-18 14:45:57",
"consignee": "老百",
"mobile": "17900000001",
"delivery_type": 1,
"goods_price": "40.00",
"order_amount": "40.00",
"discount_amount": "0.00",
"integral_amount": "0.00",
"total_amount": "40.00",
"total_num": 1,
"shipping_price": "0.00",
"shipping_time": "",
"user_remark": "",
"confirm_take_time": "",
"cancel_time": "",
"refund_status": 0,
"settle_id": 0,
"settle_amount": null,
"use_integral": 0,
"refund_amount": null,
"order_remarks": "",
"create_time": "2023-01-18 14:45:57",
"update_time": null,
"coupon_list_id": null,
"team_found_id": 0,
"team_id": 0,
"delivery_id": 0,
"attach_values": "{\"give_integral_scene\":1,\"give_growth_scene\":1,\"give_growth_num\":0,\"give_integral_num\":0}",
"team": [],
"order_goods": [
{
"id": 48,
"order_id": 47,
"goods_id": 1,
"item_id": 1,
"goods_name": "晨光中性笔笔芯黑0.5mm黑色碳素签字笔GP-1008按动式水笔学生考试用蓝黑医生处方笔教师专用红笔圆珠笔文具",
"goods_num": 1,
"goods_price": "40.00",
"member_price": "44.82",
"original_price": "44.82",
"total_price": "40.00",
"total_pay_price": "40.00",
"discount_price": "0.00",
"integral_price": "0.00",
"spec_value_ids": "1",
"refund_status": 0,
"is_comment": 0,
"is_seckill": 1,
"is_member": 0,
"member_discount": "0.00",
"goods_info": "{\"item_id\":1,\"goods_id\":1,\"goods_name\":\"晨光中性笔笔芯黑0.5mm黑色碳素签字笔GP-1008按动式水笔学生考试用蓝黑医生处方笔教师专用红笔圆珠笔文具\",\"status\":1,\"del\":0,\"image\":\"\\/upb6bb2224e4051ecf407cabb54cd781.png\",\"is_integral\":0,\"is_member\":0,\"give_integral_type\":0,\"give_integral\":null,\"free_shipping_type\":1,\"free_shipping\":\"0.00\",\"free_shipping_template_id\":0,\"spec_image\":\"\",\"spec_value_str\":\"默认\",\"spec_value_ids\":\"1\",\"goods_price\":\"40.00\",\"volume\":\"2.000\",\"stock\":9818,\"weight\":\"2.000\",\"first_category_id\":1,\"second_category_id\":4,\"third_category_id\":9,\"goodnum\":\"1\",\"image_str\":\"http:\\/\\/101.43.8.10:6969\\/uploads\\/images\\/background\\/20201210\\/45b6bb2224e4051ecf407cabb54cd781.png\",\"is_seckill\":1,\"discount_price\":0,\"integral_price\":0,\"original_price\":\"44.82\",\"member_price\":\"44.82\",\"is_show_member\":0,\"give_integral_num\":0,\"sub_price\":40}",
"create_time": 1674024357,
"comment_btn": 0,
"refund_btn": 0,
"spec_value": "默认",
"image": "http://101.43.8.10:6969/uploads/images/background/20201210/45b6bb2224e4051ecf407cabb54cd781.png"
}
],
"delivery_address": "北京北京市东城区东直门内大街1号",
"pay_btn": 0,
"cancel_btn": 1,
"delivery_btn": 0,
"take_btn": 0,
"del_btn": 0,
"order_cancel_time": "",
"pay_way_text": "余额支付"
},
"show": 0,
"time": "0.073664"
}
2023-01-18 14:45:57,946 PLS自动化测试 INFO assert_util.py [20] 从Excel中提取的断言字段:[{'expr': '$.msg', 'expected': '获取成功', 'type': 'eq'}]
2023-01-18 14:45:57,946 PLS自动化测试 INFO assert_util.py [23] 要断言的内容为:{'expr': '$.msg', 'expected': '获取成功', 'type': 'eq'}
2023-01-18 14:45:57,946 PLS自动化测试 INFO assert_util.py [28] 从响应结果中提取到的值为:获取成功
2023-01-18 14:45:57,946 PLS自动化测试 INFO assert_util.py [29] 期望结果为:获取成功
2023-01-18 14:45:57,946 PLS自动化测试 INFO assert_util.py [32] 提取值与期望结果的断言结果为:True
2023-01-18 14:45:57,947 PLS自动化测试 INFO assert_util.py [42] 断言成功!
PASSED
=================================================================================================== 11 passed in 2.26s ====================================================================================================
Report successfully generated to /Users/laobai/workspaces/testdemo_pytest/report/html
打开生成的测试报告

注:在excel的测试数据设计中,可以增加一列重要级别,可以在程序中设计成对应到allure的报告中的级别分布图,这里不进行具体的实现。
提取登录到conftest
在做流程测试时,登录会被频繁使用,可以讲登录请求提到conftest.py
文件中,
import pytest
from common.pl_requests import PLRequests
from common.data_util import Data
from common.config_util import ConfigYaml
@pytest.fixture(scope="session")
def login_init():
pl_requests = PLRequests()
cy = ConfigYaml()
url = cy.get_normal_login_url()
data = {
'account': cy.get_normal_usrename(),
'password': cy.get_normal_password(),
'client': 2
}
res = pl_requests.pl_request(method=cy.get_normal_method(), url=url, data=data)
token = res.json()['data']['token']
setattr(Data, "token", token)
yield
用于有2个测试用例,登录的测试用例用不到conftest.py中的登录方法,即在test_order_flow的类中进行引用调用
import pytest
import os
import allure
from common.pl_requests import PLRequests
from common.excel_util import ExcelReader
from common.path_util import get_data_path
from common.config_util import ConfigYaml
from common.assert_util import pl_assert
from common.extract_util import extract_data_from_response
from common.pl_util_plus import replace_case_with_re, data_cleaning
from common.log_util import pl_log
PLRequests = PLRequests()
conf_y = ConfigYaml()
@allure.epic("LikeShop商城")
@allure.feature("流程测试")
@pytest.mark.usefixtures("login_init")
class TestOrderFlow:
reader = ExcelReader(get_data_path() + os.sep + conf_y.get_file_name('order_flow'),
conf_y.get_sheet_name('order_flow'))
cases = reader.read_data()
@pytest.mark.parametrize("cases", cases)
def test_order_flow(self, cases):
# 从excel读取到的每一行数据,先进行变量替换,再进行整理
new_cases = data_cleaning(replace_case_with_re(cases))
allure.dynamic.story(new_cases["模块"])
allure.dynamic.title(new_cases["测试用例ID"] + "_" + new_cases["接口名称"])
allure.dynamic.description(
"请求地址:" + new_cases["url"] + "\n请求方法:" + cases["请求方法"] + "\n请求数据:" + cases["请求数据"] + "\n响应体提取器:" + str(
cases["extract"]) + "\n预期结果断言表达式:" +
cases["期望结果断言"])
response = PLRequests.pl_request(method=new_cases["请求方法"], url=new_cases["url"], headers=new_cases['Headers'],
params=new_cases['请求数据'], data=new_cases['请求数据'], json=new_cases["请求数据"])
pl_assert(new_cases["期望结果断言"], response.json())
# 在有extract列的请求的响应结果中提取数据,并设置为全局变量
if new_cases["extract"]:
extract_data_from_response(new_cases["extract"], response.json())
pl_log.info("从接口请求中获取全局变量提取表达式为:{}".format(new_cases["extract"]))
修改excel,删除order_flow中的登录用例,并重新编辑用例ID

执行用例并生成报告,flow流程中已经没有登录了
