# api_test_framework **Repository Path**: michelle33/api_test_framework ## Basic Information - **Project Name**: api_test_framework - **Description**: pytest + requests + FastAPI mock 的 API 自动化测试框架 — 32 用例全绿,三级 fixture 分层 + function 级数据隔离 + 响应解析防御层 - **Primary Language**: Unknown - **License**: MulanPSL-2.0 - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-08-26 - **Last Updated**: 2026-09-01 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # API 自动化测试框架(pytest + requests + FastAPI mock) 配套文章:《API 测试 Agent 发布后,我用 3 天把配套 pytest 脚手架跑了 32 个用例,说说真实踩坑》 关注公众号「智测开发手记」 ## 这是什么 一个 **pytest + requests + FastAPI mock_server** 的 API 自动化测试脚手架,开箱即跑 32 个用例全绿。不是 Hello World demo,是带订单状态机、库存扣减恢复、越权防护的真实业务流测试。 与常见的"一个 test_*.py 写 5 个 assert"不同,本脚手架做的是**框架级能力**: ``` 三级 fixture 分层 → function 级数据隔离 → 响应解析防御层 → YAML 数据驱动 → --env 多环境切换 ``` 适合中小团队作为 API 自动化的起点,直接往上加自己业务的用例即可。 ## 快速开始 ```bash # 1. 克隆仓库 git clone https://gitee.com/michelle33/api_test_framework.git cd api_test_framework # 2. 安装依赖(建议用 venv) python3 -m venv .venv source .venv/bin/activate pip install -r requirements.txt # 3. 启动被测网站(终端 1,后台运行) cd mock_server && python3 run.py # 默认 http://127.0.0.1:8000 # 4. 运行测试(终端 2,回到框架根目录) pytest # 默认 test 环境,32 用例全绿 pytest --env=dev # 切换环境(命令行覆盖配置) pytest -m business # 只跑业务流用例 pytest -n auto # 并行执行(pytest-xdist) ``` 生成 Allure 报告: ```bash pytest --alluredir=reports/allure-results allure serve reports/allure-results ``` ## 目录结构 ``` api_test_framework/ ├── README.md # 本文件 ├── TESTING_REPORT.md # 回归测试记录 ├── requirements.txt # Python 依赖 ├── pyproject.toml # IDEA/PyCharm 识别 source_root ├── pytest.ini # markers / alluredir / pythonpath ├── conftest.py # 根级 fixture + --env 参数 + 数据隔离 autouse ├── common/ # 公共层:HTTP 客户端 / 鉴权 / 日志 │ ├── client.py # 封装 get/post + 响应解析防御层 │ ├── auth.py # token 管理 │ └── logger.py # 统一日志 ├── config/ # 配置层:settings + env/{dev,test,prod}.yaml │ └── settings.py # 环境切换 + YAML 加载 ├── data/ # 测试数据:login_data.yaml / order_data.yaml ├── apis/ # 接口封装层(Page Object 模式) │ ├── login_api.py # 登录接口 │ ├── product_api.py # 商品接口 │ └── order_api.py # 订单接口 ├── fixtures/ # 业务 fixture │ ├── session_fixtures.py # session 级:HTTP 客户端 + token │ └── function_fixtures.py # function 级:数据清理 + 测试订单 ├── utils/ # 工具层 │ ├── data_builder.py # 测试数据构造 │ └── db_helper.py # 数据清理 ├── tests/ # 测试用例 │ ├── test_login.py # 8 个登录用例 │ ├── test_product.py # 4 个商品用例 │ └── test_order_flow.py # 20 个订单业务流用例 └── mock_server/ # Demo 被测网站(FastAPI 电商 API) ├── run.py # 统一入口:python3 run.py └── app/ # FastAPI 应用(订单状态机 + 库存扣减) ``` ## 32 个用例明细 | 模块 | 用例数 | 覆盖点 | |------|------:|------| | 登录(test_login.py) | 8 | 空参 400 / 密码错 401 / 禁用 403 / 正常拿 token / 越权账号 / 刷新 token / 重复登录 / YAML 数据驱动 3 组账号 | | 商品(test_product.py) | 4 | 未登录 401 / 正常列表 / 商品详情 / 不存在商品 404 | | 订单业务流(test_order_flow.py) | 20 | 下单→扣库存→支付→查询 PAID / 取消恢复库存 / 已支付不可取消 409 / 重复支付 409 / 库存不足 / 库存为 0 / 未登录下单 401 / 越权他人订单 404 / 空金额 / 负金额 / 非法商品 ID / 并发下单 / 数据驱动 5 组场景 | | **合计** | **32** | — | ### 健康度(2026-08-24 最新回归) ```bash python3 -m py_compile $(find . -name "*.py") # 0 语法错误 python3 -m pytest --collect-only # 32 items collected python3 -m pytest -v # 32 passed in 0.66s python3 -m pytest -n auto # 32 passed(4 进程并行) ``` ## Demo 被测网站(mock_server) 一个带业务规则的电商 API,测试用例跑的就是它的真实业务流: | 接口 | 说明 | |------|------| | `POST /api/login` | 登录,返回 token(空参数 400 / 密码错 401 / 禁用 403) | | `GET /api/products` | 商品列表(需登录) | | `POST /api/orders` | 下单:校验库存、扣减库存(预占) | | `POST /api/orders/{id}/pay` | 支付:CREATED→PAID,重复支付 409 | | `POST /api/orders/{id}/cancel` | 取消:CREATED→CANCELLED 并恢复库存,已支付不可取消 409 | | `POST /api/admin/reset` | 重置测试数据(框架的数据隔离用) | 种子账号:`admin/admin123`、`alice/pass123`、`bob/pass456`(`locked/locked123` 为禁用账号) ## 关键设计 1. **环境隔离**:`TEST_ENV` 环境变量或 `pytest --env` 切换,默认 `test` 2. **三级 fixture**:session 级(HTTP 客户端 + token)/ function 级(数据清理 + 测试订单) 3. **数据隔离**:每个用例自动 `reset` mock 数据(等价真实项目的 truncate + 恢复种子) 4. **响应解析防御层**:优先看 Content-Type 再决定 json 解析,404 HTML 不再炸 `JSONDecodeError` 5. **失败可定位**:用例失败自动打印最后一次请求/响应体 6. **数据驱动**:登录、下单场景全部走 YAML 参数化,`ids` 用业务 id 提升报告可读性 ## 落地建议 1. **先跑绿 32 个用例**:clone 下来第一件事是确认本地能跑通,再往上加自己业务用例 2. **mock_server 只是 demo**:真实项目把 `apis/` 里的接口换成你被测系统的接口,`base_url` 改到 `config/env/test.yaml` 3. **数据隔离要前置**:每个用例都假设前一个用例没跑过,不要信"我前面的用例就是不碰这个字段" 4. **响应解析一定要防御性编程**:`Content-Type` 优先于"我猜对方返回 json",`response.json()` 外面一定要包 try ## 限制说明 - 本脚手架是**框架级参考实现**,不是生产级测试平台 - mock_server 是 demo 电商 API,真实项目需要替换为你自己的被测系统 - 并发用例数 > 4 时建议用 `pytest -n auto`,但确保 mock_server 能扛住并发 - Allure 报告需要单独安装 `allure` 命令行工具(`brew install allure`) ## 故障排查 | 现象 | 排查方向 | |---|---| | `ModuleNotFoundError: No module named 'common'` | 在项目根目录执行 pytest,不要 cd 到子目录 | | mock_server 启动报 `Address already in use` | 上次没关干净,`lsof -i:8000` 找进程 kill 掉 | | 用例偶发失败、库存数不对 | 检查 `conftest.py` 的 `reset_mock_data` fixture 是否生效 | | `response.json()` 抛 `JSONDecodeError` | 已修复,确认 `common/client.py` 走的是 `parse_response` | | IDEA 打开全红 | 确认根目录有 `pyproject.toml`,`pythonpath = ["."]` 已配置 | | Windows 下路径问题 | 脚本用 `pathlib`,不要用字符串拼路径 | ## License MIT — 自由使用、修改、分发。如果对你有帮助,关注「智测开发手记」 #### 简介 pytest + requests + FastAPI mock 的 API 自动化测试框架 — 32 用例全绿,三级 fixture 分层 + function 级数据隔离 + 响应解析防御层