基于 Python + YAML 配置驱动的接口自动化测试框架

Api-Lite

基于 Python + YAML 配置驱动的接口自动化测试框架。

当前项目只保留本地 Product Demo,不包含真实业务接口。Demo 后端在本地启动,接口统一使用 /api/demo/...,用于演示接口授权、参数传递、断言校验、跨接口数据传递和增删改查闭环。


核心特性

  • 配置驱动:接口定义、请求参数、断言规则都放在 YAML 中维护。
  • 统一封装:业务 API 类继承 BaseAPI,复用请求发送、断言、异常处理逻辑。
  • 自动 token:框架启动时调用 token 接口,自动把 token 写入 Authorization 请求头。
  • 参数覆盖:支持默认参数和用例数据合并,适合复用接口模板。
  • 占位符替换:测试数据支持 {timestamp}{date}{time}
  • 顺序控制:通过 @priority 控制测试用例执行顺序。
  • 请求日志:记录请求 URL、Header、Params、JSON、响应内容和耗时。
  • 自动重试:对 500、502、503、504、429 等状态码进行重试。
  • HTML 报告:通过 run_case.py 生成测试报告。
  • 本地闭环 Demo:内置本地后端服务,开箱即可跑通 token + CRUD。

项目结构

.
├─ apis/
│  └─ products_api.py                 # Product API 封装层
├─ case/
│  └─ test_products_demo.py           # Product 闭环测试用例
├─ demo_server/
│  ├─ server.py                       # 本地 demo 后端服务
│  └─ README.md                       # 本地 demo 后端说明
├─ framework/                         # HTML 报告相关依赖
├─ locust/                            # 性能测试示例入口
├─ log/                               # 请求日志和错误日志
├─ reports/                           # HTML 测试报告
├─ resources/
│  ├─ config.yaml                     # 环境配置
│  ├─ api/
│  │  └─ products.yaml                # Product 接口定义
│  └─ testdata/
│     └─ products_testdata.yaml       # Product 测试数据
├─ scripts/                           # 辅助脚本
├─ utils/
│  ├─ base_api.py                     # API 基类,请求与断言入口
│  ├─ request_utils.py                # HTTP 请求工具
│  ├─ token_manager.py                # Token 获取与缓存
│  ├─ yaml_loader.py                  # YAML 加载与配置合并
│  ├─ test_order.py                   # 用例优先级控制
│  ├─ logger.py                       # 日志工具
│  └─ exceptions.py                   # 框架异常定义
├─ requirements.txt                   # 项目依赖
└─ run_case.py                        # 统一测试运行器

框架分层

测试层
  case/test_*.py
  负责组织测试流程、读取测试数据、调用 API 封装方法

API 封装层
  apis/*_api.py
  负责封装业务动作,例如 create/list/detail/update/delete

配置层
  resources/config.yaml
  resources/api/*.yaml
  resources/testdata/*.yaml
  负责维护环境、接口定义、测试数据

工具层
  utils/*.py
  负责 token、YAML 加载、HTTP 请求、断言、日志、异常处理

本地服务层
  demo_server/server.py
  负责模拟后端 token 和 Product CRUD 接口

请求执行流程

1. 测试用例启动
   -> case/test_products_demo.py

2. 初始化 API 封装类
   -> ProductsAPI()

3. YAML 加载器读取配置
   -> resources/config.yaml
   -> resources/api/products.yaml
   -> resources/testdata/products_testdata.yaml

4. TokenManager 获取 token
   -> POST /api/demo/auth/token
   -> 返回 Bearer demo-token

5. BaseAPI 拼装接口请求
   -> base_url + path
   -> default_headers + API headers
   -> default_body + custom_data
   -> path params 替换

6. RequestUtils 发送请求
   -> 记录请求日志
   -> 执行 HTTP 请求
   -> 记录响应日志

7. BaseAPI 执行断言
   -> status_code
   -> json_path

8. 用例继续传递数据
   -> create 返回 productId
   -> list/detail/update/delete 复用 productId

快速开始

1. 安装依赖

在项目根目录执行:

pip install -r requirements.txt

2. 确认环境配置

当前项目默认使用本地 demo 环境:

current_env: local_demo

配置文件位置:

resources/config.yaml

当前环境配置:

environments:
  local_demo:
    base_url: "http://127.0.0.1:8000"
    token_url: "/api/demo/auth/token"
    timeout: 10
    retry: 3
    login_user:
      username: "demo"
      password: "demo"
      grantType: "password"

3. 启动本地 Demo 后端

打开第一个终端,在项目根目录执行:

python demo_server/server.py

启动成功后服务地址:

http://127.0.0.1:8000

浏览器直接打开该地址会返回 demo 服务说明。健康检查接口:

GET http://127.0.0.1:8000/api/demo/health

这个终端需要保持运行。

4. 运行 Product 闭环用例

打开第二个终端,在项目根目录执行:

python -m unittest case.test_products_demo -v

成功结果类似:

Ran 5 tests
OK

也可以使用统一运行器:

python run_case.py

Product Demo 闭环

测试类:

case/test_products_demo.py

执行顺序:

test_a_create  -> 新增产品
test_b_list    -> 查询产品列表
test_c_detail  -> 查询产品详情
test_d_update  -> 更新产品
test_e_delete  -> 删除产品

闭环数据流:

create 返回 productId
  -> list 通过 name 查询并提取 productId
  -> detail 使用 productId 查询详情
  -> update 使用 productId 更新数据
  -> delete 使用 productId 删除数据

覆盖的参数类型:

  • Header:Authorization: Bearer demo-tokenx-tenant-id
  • JSON body:新增、更新接口
  • Query params:列表接口
  • Path params:详情、更新、删除接口

Demo 接口说明

授权接口

POST /api/demo/auth/token

请求体:

{
  "username": "demo",
  "password": "demo",
  "grantType": "password"
}

成功响应:

{
  "code": 200,
  "message": "success",
  "data": {
    "token_type": "Bearer",
    "access_token": "demo-token"
  }
}

框架会自动拼接为:

Bearer demo-token

并写入默认请求头:

Authorization: Bearer demo-token

Product 接口

POST   /api/demo/products
GET    /api/demo/products
GET    /api/demo/products/{product_id}
PUT    /api/demo/products/{product_id}
DELETE /api/demo/products/{product_id}

Product 接口都需要授权头:

Authorization: Bearer demo-token

更多本地服务说明见:

demo_server/README.md

YAML 配置说明

环境配置

文件:

resources/config.yaml

关键字段:

current_env: local_demo

environments:
  local_demo:
    base_url: "http://127.0.0.1:8000"
    token_url: "/api/demo/auth/token"
    timeout: 10
    retry: 3
    login_user:
      username: "demo"
      password: "demo"
      grantType: "password"

default_headers:
  authorization: ""

说明:

  • current_env:当前使用的环境。
  • base_url:接口基础地址。
  • token_url:获取 token 的路径。
  • login_user:token 接口请求体。
  • default_headers.authorization:框架会自动填充 token。

接口定义

文件:

resources/api/products.yaml

示例:

create:
  name: "Create product"
  path: "/api/demo/products"
  method: "POST"
  headers:
    x-tenant-id: "DEMO"
  body_type: "json"
  default_body:
    name: ""
    sku: ""
    price: 0
    stock: 0
  assertions:
    - type: "status_code"
      expected: 200
    - type: "json_path"
      path: "code"
      expected: 200

字段说明:

  • path:接口路径,会和 base_url 拼接。
  • method:HTTP 方法。
  • headers:当前接口额外请求头。
  • body_type:请求参数类型,支持 jsonformparams
  • default_body:接口默认参数。
  • path_params:路径参数声明,例如 {product_id}
  • assertions:响应断言规则。

测试数据

文件:

resources/testdata/products_testdata.yaml

示例:

normal:
  create_product_1:
    name: "API-DEMO-Product-{timestamp}"
    sku: "SKU-{timestamp}"
    price: 99.9
    stock: 100

读取方式:

testdata = self.loader.get_testdata("products_testdata", "normal.create_product_1")

支持占位符:

  • {timestamp}:当前时间戳。
  • {date}:当前日期,格式 YYYY-MM-DD
  • {time}:当前时间,格式 HH:MM:SS

API 封装说明

文件:

apis/products_api.py

ProductsAPI 继承 BaseAPI

class ProductsAPI(BaseAPI):
    def __init__(self):
        super().__init__(module="products")

调用接口时使用统一入口:

response_json = self._handle_api_call(
    api_name="create",
    custom_data=custom_data,
)

路径参数示例:

response_json = self._handle_api_call(
    api_name="detail",
    path_params={"product_id": target_id},
)

_handle_api_call 会完成:

  • 读取 YAML 接口定义。
  • 替换路径参数。
  • 合并默认参数和用例参数。
  • 填充公共请求头和 token。
  • 发送 HTTP 请求。
  • 执行响应断言。
  • 返回响应 JSON。

用例顺序控制

文件:

utils/test_order.py

用例通过 @priority 控制顺序:

@priority(1)
def test_a_create(self):
    ...

@priority(2)
def test_b_list(self):
    ...

run_case.py 的串行模式会使用 OrderedTestLoader,按优先级执行用例。


统一运行器

文件:

run_case.py

顶部变量控制运行模式:

RUN_MODE = 1

模式说明:

0: 交互式菜单
1: 串行执行
2: 文件级并发
3: 用例级并发
4: 全部执行

执行:

python run_case.py

报告输出:

reports/api_report.html

日志和报告

日志目录:

log/

常见日志:

log/requests.log
log/error.log

报告目录:

reports/

默认 HTML 报告:

reports/api_report.html

请求日志会记录:

  • 请求方法和 URL。
  • Headers。
  • Params。
  • JSON body。
  • 响应状态码。
  • 响应 JSON。
  • 请求耗时。

新增一个接口的流程

以继续扩展 Product 模块为例:

  1. resources/api/products.yaml 中新增接口定义。
  2. resources/testdata/products_testdata.yaml 中新增测试数据。
  3. apis/products_api.py 中新增业务方法。
  4. case/test_products_demo.py 或新测试文件中新增测试用例。
  5. 启动 demo_server/server.py
  6. 运行对应测试。

新增接口定义示例:

search:
  name: "Search products"
  path: "/api/demo/products"
  method: "GET"
  body_type: "params"
  default_body:
    pageNo: 1
    pageSize: 10
    name: ""
  assertions:
    - type: "json_path"
      path: "code"
      expected: 200

常见问题

1. Token 获取失败

现象:

Token获取失败
Connection refused

原因通常是本地 demo 后端没有启动。

处理:

python demo_server/server.py

2. 端口被占用

默认端口是 8000

如果端口被占用,需要修改两个地方:

demo_server/server.py      -> PORT
resources/config.yaml      -> base_url

3. Product 用例被跳过

case/test_products_demo.py 只在 current_env=local_demo 时执行。

检查:

current_env: local_demo

4. 删除后再查不到数据

本地 demo 数据保存在内存中,删除接口执行后数据会从内存移除;重启服务后所有数据也会清空。


注意事项

  • 当前项目是 demo 版框架,不包含真实业务接口、真实账号或真实环境地址。
  • 本地 Product 数据不落库,只保存在 demo_server/server.py 进程内存中。
  • 运行测试前必须先启动本地 demo 后端。
  • 如果使用 run_case.py,建议保持 RUN_MODE = 1 进行串行闭环验证。

GitHub:Api-Lite

image
posted @ 2026-06-25 17:50  莲(LIT)  阅读(11)  评论(0)    收藏  举报