基于Requests + Pytest + Allure搭建接口测试框架


前言

基于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流程中已经没有登录了


文章作者: 老百
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 老百 !
 上一篇
Python Web UI自动化测试之Selenium基础篇 Python Web UI自动化测试之Selenium基础篇
目前提到Web UI自动化测试,最先想到的就是Selenium。Selenium支持多种浏览器、多种程序语言及多种平台,并且支持分布式,是当前最主流的Web UI测试框架。
2023-01-24
下一篇 
基于Requests + UnitTest + Excel + HTMLTestRunner搭建接口测试框架 基于Requests + UnitTest + Excel + HTMLTestRunner搭建接口测试框架
从0到1搭建完整的python+requests+unittest+excel接口自动化测试框架,使用HTMLTestRunner来生成测试报告。
2023-01-06
  目录