# pytest_interface_auto_framework **Repository Path**: mubai2323/pytest_interface_auto_framework ## Basic Information - **Project Name**: pytest_interface_auto_framework - **Description**: pytest_interface_auto_framework - **Primary Language**: Python - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 4 - **Forks**: 0 - **Created**: 2025-06-22 - **Last Updated**: 2025-12-23 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 框架介绍 本框架主要是基于 `Python` + `pytest` + `allure` + `loguru` + `yaml` + `mysql` + 飞书\企业微信\钉钉\邮箱通知 + `Jenkins` 实现的接口自动化框架。 框架主要使用 `python` 语言编写,结合 `pytest` 进行二次开发,用户仅需要在 `yaml` 文件中编写测试用例, 编写成功之后,会自动生成 `pytest` 的代码。 本框架支持多业务接口依赖,`mysql` 数据库断言和 接口响应断言,并且用例直接在`yaml`文件中维护,无需编写业务代码, 接口`pytest`框架生成`allure`报告,并且发送飞书通知,灵活配置。 # 实现功能 - 测试数据隔离, 实现数据驱动 - 支持多接口数据依赖: 如A接口需要同时依赖B、C接口的响应数据作为参数 - 数据库断言: 直接在测试用例中写入查询的sql即可断言,无需编写代码 - 动态多断言: 如接口需要同时校验响应数据和sql校验,支持多场景断言 - 自动生成用例代码: 测试人员在`yaml`文件中填写好测试用例, 程序可以直接生成用例代码 - 统计接口的运行时长: 拓展功能,订制开关,可以决定是否需要使用 - 日志模块: 打印每个接口的日志信息,同样订制了开关,可以决定是否需要打印日志 - 飞书、钉钉、企业微信通知: 支持多种通知场景,执行成功之后,可选择发送飞书、钉钉、或者企业微信、邮箱通知 - 自定义拓展字段: 如用例中需要生成的随机数据,可直接调用 # 项目结构 ```Plaintext ├── common // 公共模块,项目通用配置及结构 │ ├── __init__.py │ ├── config.yaml // 公共配置文件 │ ├── models.py // 项目中使用的数据模型定义 │ └── path_setting.py // 项目路径工具工具类 ├── config // 配置相关目录 │ ├── __init__.py │ └── db_config.yaml // 数据库配置文件 ├── data // 存放测试数据的目录 │ └── Login │ └── login.yaml // 登录模块的测试数据 ├── test_cases // 测试用例目录 │ ├── Login │ │ └── test_login.py // 登录接口的测试用例 │ └── __init__.py │ └── conftest.py // pytest 配置文件 ├── download_files // 导出下载文件目录 ├── files_store // 上传文件存放目录 ├── utils // 工具类合集 │ ├── allure_tools // Allure 报告生成工具 │ │ ├── __init__.py │ │ ├── allure_tools.py // 基本 Allure 步骤封装 │ │ └── report_data_control.py // 控制报告中附加的数据展示 │ ├── assertion_tools // 断言处理模块 │ │ ├── __init__.py │ │ ├── assert_control.py // 多类型断言控制 │ │ └── assert_type.py // 断言类型实现 │ ├── cache_tools // 缓存相关操作 │ │ ├── __init__.py │ │ └── cache_control.py // 缓存控制逻辑 │ ├── config_tools // 配置文件处理模块 │ │ ├── __init__.py │ │ └── config_control.py // YAML/JSON 配置文件的读取逻辑 │ │ └── time_control.py // 时间处理逻辑 │ ├── log_tools // 日志处理模块 │ │ ├── __init__.py │ │ ├── log_control.py // 日志核心控制逻辑 │ │ ├── log_decorator.py // 日志装饰器 │ │ └── run_time_decorate.py // 运行时间装饰器 │ ├── mysql_tools // 数据库操作模块 │ │ ├── __init__.py │ │ └── mysql_control.py // MySQL 的增删查改工具 │ ├── notify // 通知模块 │ │ ├── __init__.py │ │ ├── dingding.py // 钉钉通知 │ │ ├── lark.py // 飞书通知 │ │ ├── send_mail.py // 邮件通知 │ │ └── wechat.py // 企业微信通知 │ ├── other_tools // 其他辅助工具类 │ │ ├── __init__.py │ │ ├── exceptions.py // 自定义异常类 │ │ ├── jsonpath_data.py // 提取 jsonpath 数据工具 │ │ └── jsonpath_to_python_expr.py // jsonpath表达式转换为Python 表达式 │ ├── placeholder_tools // 占位符替换模块 │ │ ├── __init__.py │ │ └── placeholder_control.py // 替换 ${var} 占位符的核心逻辑 │ ├── read_files_tools // 文件读取与用例解析工具 │ │ ├── __init__.py │ │ ├── case_automatic_control.py // 用例自动收集与构建逻辑 │ │ ├── excel_control.py // Excel 读取逻辑 │ │ ├── get_all_files_path.py // 扫描文件路径工具 │ │ ├── get_yaml_data_analyse.py // 分析 YAML 测试用例 │ │ ├── testcase_template.py // 测试用例模板支持 │ │ └── yaml_control.py // YAML 文件读取工具 │ ├── requests_tools // 请求执行与依赖处理模块 │ │ ├── __init__.py │ │ ├── dependent_case.py // 用例依赖数据处理 │ │ ├── request_control.py // 请求核心控制类 │ │ └── set_current_request_cache.py // 当前请求缓存设置 │ ├── signature_tools // 签名模块 │ │ ├── __init__.py │ │ └── signature_control.py // 签名处理逻辑 │ └── __init__.py ├── main.py // 项目入口文件 ├── project_directory_structure.py // 打印项目目录结构的脚本 └── requirements.txt // Python 第三方库依赖库清单 ``` # 第三方依赖库 ```Plaintext allure_python_commons==2.13.5 DingtalkChatbot==1.5.7 Faker==36.1.1 jsonpath==0.82.2 loguru==0.7.3 openpyxl==3.1.5 pydantic==2.11.5 PyMySQL==1.1.1 pytest==8.3.5 PyYAML==6.0.2 requests==2.32.4 requests_toolbelt==1.0.0 sshtunnel==0.4.0 urllib3==2.4.0 ``` # 部署教程 运行本框架之前,需要先安装`Python、jdk、allure`环境 安装教程链接:`https://mubai2023.feishu.cn/wiki/EURuwKQpTiWbBTkokvFcBT53nlg` 如上环境如都搭建好,则安装本框架的所有第三方库依赖,执行如下命令: ```Plaintext pip install -r requirements.txt ``` # 开源接口文档 链接:`https://wanandroid.com/blog/show/2`, 可以用来调试、熟悉代码 # 创建测试用例 ## 创建测试用例步骤 1. 在`data`文件夹下方创建相关的`yaml`用例 2. 写完之后,需要执行 `utils\read_files_tools\case_automatic_control.py` 这个文件,生成自动化代码 3. 执行`case_automatic_control.py`文件之后,会发现,在`test_case`层新增该条用例的对应代码,可直接执行该用例调试 4. 注意,如果生成对应的测试代码之后,期间有更改过`yaml`用例中的内容,需要重新生成代码,必现因为更改`yaml`用例之后导致运行失败 5. 当所有接口都编写好之后,可以直接运行`main.py`主程序,执行所有自动化接口 ## 测试用例字段介绍 ```YAML # 公共参数 case_common: allureEpic: 必填,用作于@allure.epic()中的内容, allureFeature: 必填,用作于@allure.feature()中的内容 allureStory: 必填:用作于@allure.story()中的内容 login_01: host: ${test_host()} url: /test/v1 method: POST detail: 正常登录 headers: Content-Type: application/json request_type: json # 是否执行,空或者 true 都会执行 is_run: true data: deviceId: calculation1 params: pkg: com.test.shoot ver: 1.0.4 # 是否有依赖业务,为空或者false则表示没有 depend_switch: False # 依赖的数据 depend_case_data: - case_id: depend_case_data: depend_type: jsonpath: set_cache: replace_key: assert: error_code: jsonpath: $.code type: "==" expected_value: 200 assert_type: sql: setup_sql: db_name: current_request_set_cache: - type: response jsonpath: $.data.token name: token ``` `case_id`中的参数解释: ![](https://mubai2023.feishu.cn/space/api/box/stream/download/asynccode/?code=OGE3OWQxOTA1ZTg3NDBmZjg1ZTE1MjI5MDliZGU1MDNfUmJNaDdFSGtEaWZIakV4NWlyOHdOcWxTRzExMlNBTTZfVG9rZW46SERrV2JHYXlzb09EZXZ4bnlKT2N3VXR2bmdmXzE3NTA2MDEyMzU6MTc1MDYwNDgzNV9WNA) ![](https://mubai2023.feishu.cn/space/api/box/stream/download/asynccode/?code=MWYxNWRjM2I0NDg4YmZlMTQxM2I0YmQ1OTMxMTkyMDBfMWNRbEJuWHhlUUlldkRnVnZiUFdpcDk1M0dVSUJvcHJfVG9rZW46TXFJUGJwa3JWbzZVaEd4U3MyaWNPVnlQbmlnXzE3NTA2MDEyMzU6MTc1MDYwNDgzNV9WNA) ```YAML depend_case_data: - case_id: depend_data: - depend_type: jsonpath: set_cache: replace_key: assert: error_code: type: jsonpath: expected_value: assert_type: current_request_set_cache: - type: jsonpath: name: ``` ![](https://mubai2023.feishu.cn/space/api/box/stream/download/asynccode/?code=MTNmNGUxOTAzMzdhZjlmOGUyZWY2YTQ5Yzc0YjFmZGZfQ0Ywb29hMVRPeHRsSmpWT2FjcFJrZ29XUEtDbngxMDFfVG9rZW46UEVmb2JjbkZmb2NBR3Z4TDVkZ2NHbWRlbnpiXzE3NTA2MDEzNjY6MTc1MDYwNDk2Nl9WNA) ![](https://mubai2023.feishu.cn/space/api/box/stream/download/asynccode/?code=NzRiNjMzM2E1MjRmOWRhNjFhYTMyMWMxZGI1MzUwNmVfVUhqOHViQ0ZDTzhFbU5VTkkzSG00U01DNnloUUlVcGlfVG9rZW46WEdmYWJrbGNrb3lsTG94NlptMWNlYXMzbllnXzE3NTA2MDEzNjY6MTc1MDYwNDk2Nl9WNA) ### 用例中需要依赖登录的token 首先,为了防止重复请求调用登录接口,`pytest`中的 `conftest.py` 提供了热加载机制,我们需要在 `conftest.py` 提前编写好登录的代码,将登录的`token`存入缓存中。 编写好之后,我们会在 `request_control.py` 文件中,读取缓存中的`token`,如果该条用例需要依赖`token`,则直接进行内容替换。 ```Python @pytest.fixture(scope="session", autouse=True) def work_login_init(): """ 获取登录的cookie :return: """ url = "https://test/user/login" data = { "username": 18800000001, "password": 123456 } headers = {'Content-Type': 'application/json'} # 请求登录接口 res = requests.post(url=url, data=data, verify=True, headers=headers).json() token = res['response']['token'] CacheHandler.update_cache(cache_key='work_login_init', cache_value=token) ``` 然后在编写用例的时候,`token` 填写我们所编写的缓存名称即可。 ```YAML # 公共参数 case_common: allureEpic: 必填,用作于@allure.epic()中的内容, allureFeature: 必填,用作于@allure.feature()中的内容 allureStory: 必填:用作于@allure.story()中的内容 login_01: host: ${test_host()} url: /test/v1 method: POST detail: 正常登录 headers: Content-Type: application/json Authorization: Bearer ${work_login_init} ``` ### 数据依赖 #### 数据依赖概述 数据依赖处理模块用于解决测试用例之间的数据依赖关系,本框架支持从数据库、其他接口响应或请求中提取依赖数据,并将其应用于当前测试用例。该模块通过统一的接口处理不同类型的依赖,确保测试用例的独立性和可维护性。 #### 依赖类型说明 | 依赖类型 | 说明 | | -------- | --------------- | | response | 从其他接口的响应中获取依赖数据 | | request | 从其他接口的请求中获取依赖数据 | | sql | 从数据库查询中获取依赖数据 | #### 依赖数据配置说明 1. 依赖开关配置 ```YAML test_case: depend_switch: True # 启用依赖处理,默认为False ``` 2. 依赖用例配置 ```YAML depend_case_data: - case_id: get_user_info # 依赖的用例ID depend_data: - depend_type: response # 依赖类型 jsonpath: $.data.user_id # JSONPath表达式,用于提取数据 set_cache: user_id # 缓存键名,可选 replace_key: $.data.user_id # 替换键名,可选 ``` #### 多业务依赖场景说明 ##### **依赖同一个接口的单个数据** 依赖响应数据:B接口某个参数依赖于A接口响应数据中的某个字段 简单举个例子,比如查询订单接口,需要订单ID,在查询订单之前需要先创建订单,创建订单接口返回订单ID。 1. 首先需要创建`create_order.yaml`的文件 ```YAML case_common: allureEpic: 拼夕夕APP allureFeature: 购物车 allureStory: 创建订单 create_order_01: host: ${test_host()} url: /capital/shopping/creat_order method: POST detail: 创建订单 headers: Content-Type: application/json request_type: json is_run: true data: channelId: e351d5cf-ef82-4e43-ade7-bd084f1667e7 params: depend_switch: False depend_case_data: assert: error_code: jsonpath: $.code type: "==" expected_value: 200 assert_type: null sql: null setup_sql: null db_name: null current_request_set_cache: null ``` 2. 创建好之后,再创建一个查询订单`get_transaction_item.yaml`的yaml ```YAML case_common: allureEpic: 拼夕夕APP allureFeature: 订单中心 allureStory: 查询订单信息 get_transaction_item_01: host: ${test_host()} url: /transaction/item/get method: GET detail: 查询订单信息 headers: request_type: params is_run: true data: params: orderId: $cache{orderid} depend_switch: True depend_case_data: - case_id: create_order_01 depend_data: - depend_type: response jsonpath: $.data.orderId set_cache: orderid assert: error_code: jsonpath: $.code type: "==" expected_value: 200 assert_type: null sql: null setup_sql: null db_name: null current_request_set_cache: null ``` 其中处理多业务数据依赖的核心配置如下: ```YAML params: orderId: $cache{orderid} # 依赖数据中自定义的缓存名称 depend_switch: True # 是否有依赖业务,为空或False表示没有依赖 # 依赖的数据 depend_case_data: - case_id: create_order_01 # 依赖的测试用例ID depend_data: - depend_type: response # 依赖的类型,此处是依赖create_order_01用例的响应数据 jsonpath: $.data.orderId # 从依赖类型对应的数据中提取指定字段的jsonpath表达式 set_cache: orderid # 自定义的缓存名称,将提取出来的数据缓存起来 ``` 1. 当前用例有依赖数据的时候,首先需要将`depend_switch`设置为`True`,开启依赖开关,并配置`depend_case_data`相关的依赖数据: 2. `case_id`:依赖的测试用例ID,比如查询订单信息依赖的是创建订单这条用例,这里就填写创建订单的用例ID。 3. `depend_data`:是依赖数据的具体配置,列表类型,支持多个依赖数据 1. `depend_type`:依赖的类型,有`response`、`request`和`sql`三种类型 2. `jsonpath`:字符串类型,`jsonpath`提取表达式,用于从依赖类型对应的数据中提取指定的字段,比如查询订单依赖创建订单接口响应数据中返回的订单ID,这里就填写从创建订单接口响应数据中提取订单ID的`jsonpath`表达式。 3. `set_cache`:字符串类型,自定义的缓存名称,从创建订单接口提取出来订单ID后,需要将这个ID缓存起来,然后在查询订单接口需要用到这个订单ID的地方引用这个缓存的订单ID,引用格式为:`$cache{自定义的缓存名称}`,这里是orderId需要具体的订单ID,所以填写的值是`set_cache`自定义的缓存名称,`$cache{orderid}` ##### 依赖同一个接口的多个数据 如下:`depend_data`的值是列表类型,支持多个依赖数据填写 ```YAML depend_case_data: - case_id: create_order_01 # 依赖的测试用例ID depend_data: - depend_type: response jsonpath: $.data.orderId set_cache: orderid # 自定义的缓存名称,将提取出来的数据缓存起来 - depend_type: response jsonpath: $.data.status set_cache: status # 自定义的缓存名称,将提取出来的数据缓存起来 ``` ##### 依赖不同接口的数据 假设在查询订单信息之前,需要先查询商品列表,再创建订单这两个接口的数据,配置如下: ```YAML depend_case_data: - case_id: product_list_01 depend_data: - depend_type: response jsonpath: $.data.channelId set_cache: channelId - case_id: create_order_01 depend_data: - depend_type: response jsonpath: $.data.orderId set_cache: orderid ``` ##### 请求参数中需要依赖数据 如下,我们的参数在请求头中,所以在`depend_case_data`中获取需要的依赖数据,并将需要的数据存入缓存,然后在请求头`headers`中引用缓存数据即可 ```YAML case_common: allureEpic: 获取用户信息接口 allureFeature: 认证模块 allureStory: 用户信息 user_info_01: host: ${{host()}} url: /auth/user_info method: GET detail: 获取用户信息 headers: Authorization: "Bearer $cache{token}" request_type: params is_run: true data: null params: depend_switch: true depend_case_data: - case_id: login_01 depend_data: - depend_type: response jsonpath: $.data.token set_cache: token assert: error_code: jsonpath: $.code type: "==" expected_value: 200 assert_type: null sql: null setup_sql: null db_name: null current_request_set_cache: null ``` ##### 依赖数据来自于数据库 当前框架数据依赖设计中,对于接口依赖,是通过`case_id`从缓存中获取依赖的用例数据,然后发送请求,但是当依赖为数据库依赖时,直接执行SQL查询,不需要接口请求。所以当依赖类型为sql时,`case_id`需要设置为`db`,同时填写需要的`setup_sql`(列表类型),用来从数据库中查询数据,配置如下: ```YAML case_common: allureEpic: 拼夕夕APP allureFeature: 资金模块 allureStory: 查询订单信息 user_info_01: host: ${test_host()} url: /transaction/item/get method: GET detail: 查询交易状态 headers: request_type: params is_run: true data: null params: transactionId: $cache{orderId} depend_switch: true depend_case_data: - case_id: db depend_data: - depend_type: sql jsonpath: $.order_id # 从数据库中查询出来的数据使用jsonpath提取 set_cache: orderId # 将提取出来的数据存入缓存 assert: error_code: jsonpath: $.code type: "==" expected_value: 200 assert_type: null sql: null setup_sql: - "SELECT * from transaction_order where idfv = 'D3BA8C8C-DF14-4ADA-8C7D-00F354AC3B2C';" db_name: null current_request_set_cache: null ``` ### 用例中使用随机数据 工作中有些接口在请求的时候,可能需要按照指定规则生成随机数据,比如`UUID`。当前框架中预先设置了几种随机函数,如果需要扩展,可以在`utils`-`placeholder_tools`-`placeholder_control.py`中的`FakerData`类里扩展需要的随机函数。 比如,`FakerData`类中有下面这个随机函数: ```Python def get_random_str(self, min_length: int = 8, max_length: int = 16) -> str: """ 生成随机字符串 :param min_length: 字符串最小长度 :param max_length: 字符串最大长度 :return: 随机字符串 """ return self.faker.pystr(min_chars=min_length, max_chars=max_length) ``` 那么在`yaml`测试用例文件可以使用**`${随机函数}`**格式来**引用**对应的**随机函数**。 随机函数支持传递参数,也支持不传参数。 ```YAML name: ${get_random_str(2,5)} ``` ### 断言方法 | 断言type | 对应方法 | 断言说明 | | ------ | ------------------------ | ----------------------- | | "==" | equals() | 判断实际结果和期望结果相等 | | "不等于" | not_equals() | 判断实际结果不等于预期结果 | | "包含" | contains() | 判断实际结果内容中包含期望结果 | | "不包含" | not_contains() | 判断实际结果内容不包含期望结果 | | "大于" | greater_than() | 判断实际结果大于预期结果 | | "大于等于" | greater_than_or_equals() | 判断实际结果大于等于预期结果 | | "小于" | less_than() | 判断实际结果小于预期结果 | | "小于等于" | less_than_or_equals() | 判断实际结果小于等于预期结果 | | "开头" | startswith() | 检查响应内容的开头是否和预期结果内容的开头相等 | | "结尾" | endswith() | 检查响应内容的结尾是否和预期结果内容相等 | #### 断言概述 本框架提供了灵活的断言机制,支持对 HTTP 状态码、响应数据、请求数据以及数据库数据进行断言验证,并支持与 SQL 查询结合的高级断言场景。 #### 断言配置整体结构 YAML 测试用例中断言相关配置通常包含以下部分: - `assert`:核心断言配置,包含状态码和数据断言 - `sql`(可选):独立 SQL 执行配置,可与断言配合使用 ```YAML login_01: # 其它用例字段配置... assert: # 断言配置... sql: # SQL配置... ``` #### 核心断言配置(`assert` 字段) ```YAML assert_data: # 状态码断言(必填) status_code: 200 # 断言配置示例 response_assert: # 响应数据断言 type: "==" # 断言方法(必填) jsonpath: "$.data.name" # 提取路径(必填) expected_value: "测试用户" # 期望值(必填) assert_type: None # 断言类型(可选,默认None为响应断言) msg: "名称验证失败" # 错误提示信息(可选) db_assert: # 数据库断言(需开启SQL开关) type: "包含" # 断言方法 jsonpath: "$.data.id" # 从响应数据中提取目标值 expected_value: # res_sql/req_sql类型下此参数非必填 assert_type: res_sql # 响应与数据库比较 msg: "ID不存在于数据库" request_assert: # 请求数据断言 type: "不等于" # 断言方法 jsonpath: "$.params.id" # 从请求数据中提取目标值 expected_value: # res_sql/req_sql类型下此参数非必填 assert_type: req_sql # 请求与数据库比较 ``` #### 断言字段说明 ![](https://mubai2023.feishu.cn/space/api/box/stream/download/asynccode/?code=NTk1YjczZmEwZWZhNmQ5ZGExMDVlMjJiNWM4MDNmZjZfS3lFNnpmQ3ZoWmFGQktqY244VWN0VWM0VndkZDJTazZfVG9rZW46QlNObWJvQnNab2ZMS3h4TUUxbmNJSGZibkpkXzE3NTA2MDE1MTI6MTc1MDYwNTExMl9WNA) #### 断言HTTP状态码 在接口测试过程中,有些接口是没有任何响应值的,那么我们就只能通过HTTP状态码去断言这个接口了。如何断言状态码,只需在yaml文件中的assert下面添加固定字段`status_code`,然后填上预期的状态码值就行了。 ```YAML assert: status_code: 200 ``` #### 断言类型与执行流程 1. 响应数据断言(`assert_type: None`) 1. 场景:验证接口返回的 JSON 数据是否符合预期 ```YAML assert: response_data_assert: # 自定义的断言名称,建议使用英文 type: "==" jsonpath: "$.code" # # 从响应数据中提取code字段 expected_value: 200 assert_type: ``` ![](https://mubai2023.feishu.cn/space/api/box/stream/download/asynccode/?code=ZTRkNDJmNmY0NmQyN2NmOThmNjVjYzBlYmFhNTVmMmJfTEE5MExHTFRTQnVVSEY4R1JiYTFiZjZHTHllSjZuQ3pfVG9rZW46QVJZRmJEQm5yb1hnSzl4YU5CSGM4S1A4blZiXzE3NTA2MDM2MDY6MTc1MDYwNzIwNl9WNA) 2. 响应与数据库比较(`assert_type: res_sql`) 1. 场景:将接口响应数据与数据库查询结果对比 2. 前提:需开启 SQL 开关(`sql_switch: true`) ```YAML # 如果sql中需要的字段来自于响应数据,使用$sql{jsonpath表达式},从相应数据中提取对应的数据 sql: - "SELECT id FROM users WHERE id = $sql{$.user_id}" assert: db_compare_assert: type: "包含" jsonpath: "$.user_id" # 从响应数据中提取id字段 expected_value: $.id # 用于从SQL查询结果中提取用来断言数据的jsonpath表达式。 assert_type: sql ``` ![](https://mubai2023.feishu.cn/space/api/box/stream/download/asynccode/?code=ZDFlNGI5YTc4YTRlZTU1NGVlZmRiNDBmN2VjY2QwNTRfSEFleVdNeXd4bGU1VVdpdzdhbVl3NzltY1hHT0tKbGhfVG9rZW46VGlYamJFaUtOb2R1ZDB4VmxhVmNhMDJjbkRnXzE3NTA2MDM2MzI6MTc1MDYwNzIzMl9WNA) 3. 请求与数据库比较(assert_type: req_sql) 1. 场景:将请求参数与数据库查询结果对比 ```YAML # 如果sql中需要的字段来自于响应数据,使用$sql{jsonpath表达式},从相应数据中提取对应的数据 sql: - "SELECT id FROM users WHERE id = $sql{id}" assert: request_db_compare: type: "不等于" jsonpath: "$.params.id" # 从请求数据中提取id字段 expected_value: $.id # 用于从SQL查询结果中提取用来断言数据的jsonpath表达式。 assert_type: req_sql ``` ![](https://mubai2023.feishu.cn/space/api/box/stream/download/asynccode/?code=YWI4ZmZlNjAzNzkyOGE4ZGE4OWJlMTU3NWZiZjcwY2Jfd1ozaXdhVkwyaThGbDgzdlRPZ1JIam9tRWQ0bHpRVm9fVG9rZW46S21DMmJ6aW9Nb1hyNlB4ajZNZ2NSbElqbmNjXzE3NTA2MDM2NTA6MTc1MDYwNzI1MF9WNA) #### 数据库相关断言(`res_sql/req_sql`)解释 1. 配置示例 ```YAML assert: # 响应与数据库比较断言 response_db_assert: type: "==" jsonpath: "$.data.id" # 从响应中提取ID sql: "SELECT id FROM users WHERE id = '$sql{$.data.id}'" # SQL查询 assert_type: res_sql msg: "响应ID与数据库不一致" # 请求与数据库比较断言 request_db_assert: type: "不等于" jsonpath: "$.request.params.id" # 从请求中提取参数ID sql: "SELECT * FROM orders WHERE user_id = '$sql{$.request.params.id}'" assert_type: req_sql msg: "请求ID在数据库中不存在" ``` 1. 关键说明 1. - SQL占位符:使用$sql{jsonpath}从响应 / 请求中提取参数,这里的jsonpath是该条sql执行时,需要响应或请求中的某个字段的值,用于提取这个值的jsonpath表达式 ```YAML sql: - "SELECT * FROM users WHERE id = '$sql{$.data.id}'" # 响应中提取 - "SELECT * FROM orders WHERE user_id = '$sql{$.request.params.id}'" # 请求中提取 ``` **执行逻辑** - sql:响应值 vs SQL 查询结果 - req_sql:请求值 vs SQL 查询结果 - 当为数据库断言时,expected_value为提取SQL查询结果中指定字段的jsonpath表达式,用来与提取出来的响应值或请求值进行断言。 #### 注意事项 1. 断言顺序:状态码断言优先执行,数据断言按配置顺序执行 2. SQL 开关:数据库断言(`res_sql/req_sql`)需开启`sql_switch: true` 3. JSONPath 语法:严格遵循标准语法,如`$.data[0].id`表示提取数组第一个元素的 id 4. SQL 注入安全:使用`$sql{}`占位符而非直接拼接参数 5. 命名规范:自定义断言名称建议使用英文下划线命名法,确保语义清晰 ### 占位符总结 通过上面介绍,本框架占位符总共有三种,格式分别为:`$cache{自定义的缓存名称}`、`${随机函数}`和`$sql{jsonpath表达式}`,分别对应各自的使用场景。 ### 数据库连接 框架中数据库连接支持SSH隧道连接和直连数据库。 框架中数据库实现了上下文管理器,使用with语句连接,不需要手动关闭连接,自动释放资源。 数据库连接配置,需要在config添加db_config.yaml文件,文件中填写数据库连接配置信息,字段名不可更改。格式说明: ```YAML ssh_config: ssh_host: # ssh目标服务器的IP ssh_port: # 端口 ssh_username: # ssh目标服务器的用户名 ssh_password: # ssh目标服务器密码,与ssh_pkey二选一 mysql_config: user: # 连接数据库的用户名 password: # 密码 host: # 主机IP port: # 端口 ``` SSH隧道默认关闭,当使用SSH隧道连接时,MysqlControl类中ssh_switch需要设置为True。同时如果SSH隧道连接使用私钥连接,出于安全考虑,私钥地址不在yaml中配置,需要在Windows系统中:设置-系统设置-系统信息-高级系统设置-环境变量-系统变量中添加一个变量SSH_PKEY,添加后重启一下IDE即可获取对应的私钥 ### 自动生成`test_case`层代码 编写好`yaml`测试用例后,可以在`utils`-`read_files_tools`-`case_automatic_control.py`直接运行代码,运行后就会根据你设计的测试用例生成对应的测试用例代码,无需手动编写,自动生成。 ![](https://mubai2023.feishu.cn/space/api/box/stream/download/asynccode/?code=YzJmNzU3ZGU2ZTdmOGU3Y2YxMDhmNjZkNTc0OWNjNmVfMlNNQUhwNkZNZmFYbWV1cDZUQXpQakNlcHNmaUhqNkNfVG9rZW46THppVWIwT1hYb1VoTll4RU5tYmNLTnlibmVnXzE3NTA2MDE1ODE6MTc1MDYwNTE4MV9WNA) ### 通知 本框架支持飞书、钉钉、企业微信和邮件通知 ![](https://mubai2023.feishu.cn/space/api/box/stream/download/asynccode/?code=MzgyYzQ4ZGNlODViN2ZjZTljYWJhMTQ0NGUzMGZmYmVfdjFQVEVORDFsdWxJMTU2c3dIVlh0Y1ZSVjd6eWZSSDZfVG9rZW46UDN4eWI2QlVsb0VoVGJ4eGw4ZWNQcTlJbktmXzE3NTA4NTg0MTY6MTc1MDg2MjAxNl9WNA) ![](https://mubai2023.feishu.cn/space/api/box/stream/download/asynccode/?code=OGUyYjQ0YmQ0NTEwZTU4YmJiYTgxMmQwNjYxMzhlMjZfT3A2VHBIRUpFVnVublNVbHFnTlJjVmpsWlpGSk9UZDNfVG9rZW46WFl0WGJ3cTdnb1g2VmZ4ZjB1aGNFTzBKbk9mXzE3NTA4NTg0MTY6MTc1MDg2MjAxNl9WNA) #### 企业微信 ![](https://mubai2023.feishu.cn/space/api/box/stream/download/asynccode/?code=YzM3ZGU5ZTZiZmVlNWZmNDRhNDljMjRkMjExYjVkNDFfWUtXNW9jcGtjOHNPV2dnaFI4cUhnUGZtNDJFUWRadXZfVG9rZW46WXNDYWJ6bDhFb1k3aHl4V3d3S2NEUUhabnhGXzE3NTA4NTg0ODc6MTc1MDg2MjA4N19WNA) #### 钉钉 ![](https://mubai2023.feishu.cn/space/api/box/stream/download/asynccode/?code=ZTI0MjIzOTE3YTZkODcxYjFiMWYwMjk1YWUzZTY2MWNfMmJrYkx2eWlsTE1EWGk5VndMcVo0MkkyNFNFYUVUU2JfVG9rZW46QVNiS2JCck5hb3o5eDh4Q3JXcGN4cWRLbk1jXzE3NTA4NTg0ODc6MTc1MDg2MjA4N19WNA) #### 邮件 ![](https://mubai2023.feishu.cn/space/api/box/stream/download/asynccode/?code=ZjAxYTZjODkwYzI0OGZlZWM4NGNkZmM0NjJkM2M4ZDlfSDVlNTNDck9IYjRkSUhwdXpiazc0V2loNHJ5NVRLNndfVG9rZW46UGhLN2JoSGttb3o5NFV4RnVYQWNUd1o2bnZ0XzE3NTA4NTg1NDM6MTc1MDg2MjE0M19WNA) ### 日志打印装饰器 在`utils`-`log_tools`-`log_decorator.py`中封装了日志装饰器,在`utils`-`requests_tools`-`request_control.py`应用,如果不需要,可以将switch设置为False,控制台将不会有对应的日志输出。 ![](https://mubai2023.feishu.cn/space/api/box/stream/download/asynccode/?code=MTU4MGFiM2JhYWUwZGY0ZDE1ZjUxMzEzMzRiYTE1NmVfNXppRkF0QnJsakVVc0NUR0JSS1k0SWhiWVhORGpOR25fVG9rZW46UllERWJmWWFJb1gycTJ4VlFjVmNJOUFUbmtnXzE3NTA2MDE2NTU6MTc1MDYwNTI1NV9WNA) ### 统计用例运行时长 同样在上图中封装了一个统计用例运行时长的装饰器,装饰器参数填写用例超时时长,单位毫秒,如果该用例执行时长超过传入时长,就会输出一条警告`warning`日志。 ### allure报告 直接运行`main.py`代码就会生成allure报告数据文件。在`main.py`中生成allure报告数据后不会自动弹出报告,因为代码注释掉了,如果需要可以恢复。 ```Python os.system("allure serve ./allure_report -h 127.0.0.1 -p 9999") ``` ### 调整用例执行顺序 在编写测试用例后,有时候需要按照指定的业务顺序执行,框架中`test_case`层的`conftest.py`文件中定义了`pytest`钩子函数`pytest_collection_modifyitems`,只需在`expected_test_case_names`列表中填入期望执行顺序的测试函数名称即可,在此列表中的测试函数,按照顺序执行,不在的按照`pytest`默认收集到的顺序执行。 ![](https://mubai2023.feishu.cn/space/api/box/stream/download/asynccode/?code=YjBhMzY0ZTQ0Y2YwYTg3ZGViZDhiOTdmZjhmZjM1NTVfQkpKUHQ2clAya25MMXNlQnI4a1pWT2xZaFpEVUhnMmxfVG9rZW46SWxUSmJVNzF6b2dpcWx4UWVPRGNwSE1SbkhoXzE3NTA2MDE2NzE6MTc1MDYwNTI3MV9WNA)