Skill: blackbat1988/apitestcreate (version 1.0.2)

--- name: api-test-create description: 当用户需要根据接口规格生成API测试分析文档时使用此技能。接受OpenAPI/Swagger文档、简化接口定义或自然语言描述，基于140个常见API测试陷阱输出全面的测试分析文档，涵盖参数校验、业务逻辑、响应验证和安全测试分析点。 --- # API测试分析文档生成器 ## 目的 根据接口规格定义生成全面的API测试分析文档。将API定义转换为结构化的测试分析，确保覆盖参数校验、业务逻辑、响应验证和常见陷阱的测试点分析。 ## 使用时机 在以下情况下使用此技能： - 为新API端点设计测试策略时 - 审查API测试覆盖完整性时 - 需要测试分析文档供团队评审时 - 针对常见陷阱审计API质量时 - 生成测试方案和测试点清单时 ## 工作流程 ### 步骤1：解析接口定义 从输入中提取： 1. **基本信息**：端点路径、HTTP方法、描述 2. **请求参数**：名称、类型、约束、必填/可选 3. **返回字段**：名称、类型、描述 4. **业务规则**：校验规则、状态转换、权限 支持的输入格式： - OpenAPI/Swagger JSON/YAML - 简化接口定义（Markdown格式） - 自然语言描述 ### 步骤2：生成参数校验测试点分析 为每个参数基于类型生成测试点分析： | 参数类型 | 测试点分析维度 | |----------|----------------| | string | 正常值、边界长度、空值、null、特殊字符、SQL注入风险、XSS风险、Unicode字符、编码问题 | | integer | 正常值、最小/最大边界、零值、负数、小数（类型错误）、溢出、精度问题 | | number | 正常值、精度、科学计数法、边界值、NaN、Infinity | | enum | 所有有效值、无效值、大小写敏感、null、空字符串、数字枚举 | | boolean | true/false、字符串转换、数字转换、null、其他值 | | array | 空数组、单元素、多元素、最大元素数、重复元素、无效元素、嵌套数组 | | object | 完整对象、缺少必填字段、额外字段、空对象、嵌套对象深度 | | datetime | 当前时间、过去时间、未来时间、闰年、无效日期、时区、格式错误、时间精度 | ### 步骤3：生成业务逻辑测试点分析 识别规则模式并生成测试分析场景： | 规则模式 | 测试点分析 | |----------|------------| | 存在性校验 | 数据存在、不存在、已删除、逻辑删除、缓存不一致 | | 唯一性校验 | 首次创建、重复尝试、并发创建、大小写敏感、特殊字符 | | 状态转换 | 合法转换、非法转换、循环状态、终态、初始状态 | | 权限校验 | 已授权、未授权、未登录、权限变更、角色变更、越权访问 | | 关联校验 | 关联数据存在、不存在、已删除、外键约束、级联操作 | | 数量限制 | 达到上限、超过上限、低于下限、批量操作限制、分页限制 | | 时间窗口 | 有效期内、已过期、即将过期、时区影响 | ### 步骤4：生成响应验证测试点分析 | 接口类型 | 验证点分析 | |----------|------------| | 列表查询 | 结构完整性、分页字段、字段类型、空列表返回[]、null处理、排序 | | 详情查询 | 必填字段存在、字段类型正确、404处理、null字段、关联数据完整性 | | 创建 | 返回新ID、数据库验证、默认值、时间戳、返回字段完整性、状态码 | | 更新 | 成功状态、数据变更验证、未变更字段保持原值、部分更新、全量更新 | | 删除 | 成功状态、记录删除验证、软删除/硬删除、后续查询返回404、级联删除 | | 文件上传 | 文件大小限制、文件类型、空文件、超大文件、文件名、多文件 | | 文件下载 | 内容类型、文件名、文件完整性、断点续传、大文件分片 | ### 步骤5：生成安全测试点分析 **必须包含的安全测试分析**： - **SQL注入**：参数拼接、特殊字符转义、ORM框架使用、存储过程 - **XSS攻击**：输入过滤、输出转义、富文本处理、CSP策略 - **认证安全**：Token强度、Token过期、Refresh机制、会话管理、暴力破解防护 - **授权安全**：越权访问、水平越权、垂直越权、权限继承、权限缓存 - **敏感数据**：密码加密存储、身份证号脱敏、日志脱敏、传输加密 - **CSRF防护**：Token验证、Referer检查、SameSite Cookie、双重提交 - **信息泄露**：错误信息、堆栈跟踪、调试模式、敏感接口暴露 - **速率限制**：IP限流、用户限流、接口限流、突发流量、熔断降级 ### 步骤6：生成性能测试点分析 **适用时的性能测试分析**： - **响应时间阈值**：P95、P99、平均响应、最大响应、超时设置 - **大数据量处理**：分页深度、批量操作、大数据返回、内存占用 - **并发访问**：锁竞争、死锁、连接池、线程池、异步处理 - **资源消耗**：CPU、内存、磁盘IO、网络IO、文件句柄 - **缓存策略**：缓存命中率、缓存穿透、缓存雪崩、缓存一致性 - **数据库性能**：慢查询、索引使用、连接数、事务、锁等待 ### 步骤7：对照常见陷阱检查 最终确定前，验证Top 20必检项的覆盖： | 类别 | 必检项 | 分析重点 | |------|--------|----------| | 参数 | 缺少必填、类型/格式错误、边界值 | 验证是否考虑完整 | | 权限 | 未认证访问、未授权访问 | 权限矩阵是否覆盖 | | 安全 | SQL注入、XSS、敏感数据暴露 | 安全场景是否分析 | | 业务 | 幂等性、唯一性、状态转换 | 业务规则是否完整 | | 响应 | 状态码一致、字段完整、空结果 | 响应契约是否验证 | | 性能 | 响应阈值、分页限制、批量限制 | 性能指标是否定义 | 参考 `references/common-pitfalls.md` 获取完整的140点清单。 ## 输出格式 ### 单接口测试分析格式 ```markdown ## API: {接口名称} ### 基本信息 - **端点**：{METHOD} {路径} - **描述**：{接口描述} - **标签**：{Swagger标签} - **认证**：{是否需要认证} ### 请求参数分析 #### 1. {参数名} ({类型}, {必填/可选}) **约束条件**：{长度、格式、枚举值等} **参数校验测试点分析**： | 测试场景 | 测试值 | 预期结果 | 优先级 | 测试目的 | |----------|--------|----------|--------|----------| | 正常值 | {valid} | 成功 | P0 | 验证基本功能 | | 边界值-最小 | {min} | 成功 | P1 | 验证下边界 | | 边界值-最大 | {max} | 成功 | P1 | 验证上边界 | | 边界值-超过 | {max+1} | 参数错误 | P1 | 验证越界处理 | | 空值 | "" | 参数错误 | P0 | 验证空字符串 | | null | null | 参数错误 | P0 | 验证null处理 | | 特殊字符 | {special} | 参数错误 | P0 | 验证特殊字符过滤 | | SQL注入 | {sql} | 参数错误 | P0 | 验证SQL注入防护 | | XSS攻击 | {xss} | 参数错误 | P0 | 验证XSS防护 | **风险分析**：{高/中/低} #### 2. {参数名} ({类型}, {必填/可选}) ... ### 业务逻辑测试点分析 #### 场景1：{业务场景名称} **前置条件**：{条件描述} | 操作步骤 | 输入数据 | 预期结果 | 优先级 | 测试目的 | |----------|----------|----------|--------|----------| | 步骤1 | {data1} | {result1} | P0 | {purpose1} | | 步骤2 | {data2} | {result2} | P1 | {purpose2} | **业务规则验证**：{规则描述} **数据一致性检查**：{检查点} #### 场景2：{业务场景名称} ... ### 响应验证测试点分析 #### 成功响应（2xx） **状态码**：201 Created **响应体验证**： | 字段 | 类型 | 验证内容 | 优先级 | |------|------|----------|--------| | code | Integer | 等于200 | P0 | | message | String | 包含"成功" | P0 | | data | Object | 不为null | P0 | | data.id | Long | 大于0 | P0 | | data.createTime | DateTime | 不为null，格式正确 | P1 | **数据完整性验证**： - 数据库中记录已创建 - 时间戳字段自动填充 - 关联数据正确建立 #### 错误响应（4xx） **状态码**：400 Bad Request | 错误场景 | 响应体验证 | 优先级 | |----------|------------|--------| | 参数缺失 | code=400, message包含"必填" | P0 | | 参数格式错误 | code=400, message包含"格式" | P0 | | 业务规则违反 | code=409, message包含"已存在" | P0 | #### 异常响应（5xx） **状态码**：500 Internal Server Error | 异常场景 | 响应体验证 | 日志验证 | 优先级 | |----------|------------|----------|--------| | 数据库异常 | code=500, message不包含敏感信息 | 记录错误堆栈 | P0 | | 外部服务异常 | code=503, 触发熔断 | 记录熔断日志 | P1 | ### 安全测试点分析 #### 认证安全 | 测试场景 | 测试操作 | 预期结果 | 风险等级 | |----------|----------|----------|----------| | 未认证访问 | 不携带Token调用接口 | 返回401 Unauthorized | 高 | | Token过期 | 使用过期Token | 返回401, message提示Token过期 | 高 | | Token篡改 | 修改Token签名 | 返回401, message提示Token无效 | 高 | | Token刷新 | 使用RefreshToken获取新Token | 返回新Token, 旧Token失效 | 中 | #### 授权安全 | 测试场景 | 测试操作 | 预期结果 | 风险等级 | |----------|----------|----------|----------| | 越权访问 | 用户A访问用户B的数据 | 返回403 Forbidden | 高 | | 垂直越权 | 普通用户访问管理员接口 | 返回403 Forbidden | 高 | | 权限变更 | 权限变更后访问接口 | 按新权限控制 | 中 | #### 数据安全 | 测试场景 | 测试操作 | 预期结果 | 风险等级 | |----------|----------|----------|----------| | SQL注入 | 输入SQL特殊字符 | 返回400, 不被注入 | 高 | | XSS攻击 | 输入<script>标签 | 返回400, 内容被转义 | 高 | | 敏感数据泄露 | 检查响应字段 | 密码、密钥不返回 | 高 | | 日志脱敏 | 检查日志文件 | 敏感信息被脱敏 | 中 | ### 性能测试点分析 #### 响应时间要求 - **P0优先级接口**：< 200ms (95分位) - **P1优先级接口**：< 500ms (95分位) - **P2优先级接口**：< 1000ms (95分位) - **P3优先级接口**：< 2000ms (95分位) #### 压力测试场景 | 场景 | 并发数 | 持续时间 | 预期结果 | 关注点 | |------|--------|----------|----------|--------| | 基准测试 | 1 | 10分钟 | 响应稳定 | 基准响应时间 | | 负载测试 | 10 | 30分钟 | 成功率>99.9% | 系统负载 | | 压力测试 | 50 | 15分钟 | 成功率>99% | 系统瓶颈 | | 峰值测试 | 100 | 5分钟 | 不崩溃 | 最大承载 | #### 性能监控指标 - **响应时间**：平均、P95、P99、最大值 - **吞吐量**：TPS、QPS - **错误率**：4xx、5xx比例 - **资源使用率**：CPU、内存、磁盘IO、网络IO - **数据库指标**：连接数、慢查询、锁等待 ### 兼容性测试点分析 #### 客户端兼容性 | 客户端类型 | 版本范围 | 测试重点 | 优先级 | |------------|----------|----------|--------| | Web浏览器 | Chrome, Firefox, Safari, Edge | 最新+前2个版本 | P1 | | 移动端 | iOS, Android | 主流版本 | P2 | | 桌面应用 | Windows, macOS, Linux | 主流版本 | P2 | #### 数据格式兼容性 | 格式类型 | 测试内容 | 预期结果 | 优先级 | |----------|----------|----------|--------| | JSON | 标准JSON、嵌套对象、数组 | 正确解析 | P0 | | XML | 支持情况 | 正确解析或返回415 | P2 | | Form | application/x-www-form-urlencoded | 正确解析 | P1 | | Multipart | multipart/form-data | 正确解析 | P1 | ### 测试数据设计 #### 正向测试数据 ```json { "username": "testuser", "password": "Test123456", "email": "[REDACTED_SECRET]", "phone": "13800138000" } ``` #### 边界测试数据 ```json { "username": "a", // 最小长度 "username": "a" * 20, // 最大长度 "username": "a" * 21 // 超过最大长度 } ``` #### 异常测试数据 ```json { "username": null, // null值 "username": "", // 空字符串 "username": "<script>alert(1)</script>", // XSS "username": "admin'--", // SQL注入 "username": "../../etc/passwd" // 路径遍历 } ``` ### 测试执行建议 #### 执行优先级 1. **P0测试点**（核心功能）：100%执行，必须全部通过 2. **P1测试点**（重要功能）：100%执行，通过率>95% 3. **P2测试点**（一般功能）：80%执行，通过率>90% 4. **P3测试点**（次要功能）：50%执行，通过率>80% #### 执行阶段 - **冒烟测试**：所有P0测试点，30分钟 - **功能测试**：P0+P1测试点，2天 - **深度测试**：P0+P1+P2测试点，3天 - **回归测试**：全量测试点，1天 #### 执行环境 - **开发环境**：功能验证、快速反馈 - **测试环境**：完整测试、集成测试 - **预生产环境**：性能测试、安全测试 - **生产环境**：冒烟测试、监控验证 ### 风险分析 #### 高风险 - Token认证机制 - 权限控制体系 - 敏感数据处理 - 支付/交易接口 #### 中风险 - 业务数据完整性 - 第三方服务集成 - 文件上传下载 - 批量操作 #### 低风险 - 查询统计接口 - 只读数据接口 - 静态资源配置 ### 总结 #### 测试点统计 - 参数校验测试点：X个 - 业务逻辑测试点：X个 - 响应验证测试点：X个 - 安全测试点：X个 - 性能测试点：X个 - **总计：X个测试点** #### 测试覆盖 - 功能覆盖：100% - 参数覆盖：100% - 业务规则覆盖：100% - 安全场景覆盖：100% - 性能指标覆盖：80% #### 建议 1. 优先执行P0和P1测试点 2. 重点关注安全测试点 3. 在生产环境执行冒烟测试 4. 建立自动化测试回归套件 5. 定期评审测试点有效性 --- ``` ### 多接口测试分析格式 ```markdown # {系统名称} API测试分析报告 ## 文档信息 - **生成日期**：{date} - **接口总数**：{count} - **测试点总数**：{total_points} - **生成工具**：api-test-create v{version} ## 接口清单 | 序号 | 接口名称 | 路径 | 方法 | 优先级 | 测试点数 | |------|----------|------|------|--------|----------| | 1 | 用户注册 | /api/users | POST | P0 | 32 | | 2 | 用户登录 | /api/auth/login | POST | P0 | 28 | | ... | ... | ... | ... | ... | ... | ## 模块划分 ### 1. 认证管理模块 **接口数量**：6个 **风险等级**：🔴 高 **测试重点**：Token认证、密码安全、输入验证 **测试点数**：150+ ### 2. 产品管理模块 **接口数量**：6个 **风险等级**：🟡 中 **测试重点**：CRUD操作、数据一致性、分页逻辑 **测试点数**：120+ ## 测试策略 ### 测试优先级 - **P0（Critical）**：核心功能，必须测试通过 - **P1（High）**：重要功能，影响用户体验 - **P2（Medium）**：一般功能，优化体验 - **P3（Low）**：次要功能，可后期补充 ### 测试类型 1. **功能测试**：验证业务逻辑正确性 2. **参数测试**：验证输入验证机制 3. **安全测试**：验证安全防护能力 4. **性能测试**：验证系统性能指标 5. **兼容性测试**：验证多环境兼容性 ## 详细测试分析 ### 1.1 用户注册接口 #### 基本信息 - **端点**：POST /api/users - **描述**：创建新用户账号 - **认证**：否 - **模块**：认证管理 #### 参数校验测试点分析 ... #### 业务逻辑测试点分析 ... （后续内容同单接口格式） ## 测试数据设计 ### 正向数据 ```json { "username": "valid_user", "password": "Valid123", "email": "[REDACTED_SECRET]" } ``` ### 边界数据 ```json { "username": "a", // 最小长度 "username": "a" * 20, // 最大长度 "username": "a" * 21 // 超过最大长度 } ``` ### 异常数据 ```json { "username": null, // null值 "username": "", // 空字符串 "username": "<script>", // XSS "username": "admin'--" // SQL注入 } ``` ## 测试执行建议 ### 第一阶段：冒烟测试（2小时） 执行所有P0测试点，验证核心功能 ### 第二阶段：功能测试（2天） 执行P0+P1测试点，覆盖主要业务场景 ### 第三阶段：深度测试（3天） 执行P0+P1+P2测试点，包括性能和安全 ### 第四阶段：回归测试（1天） 全量测试点回归，确保修改不影响已有功能 ## 测试环境要求 ### 硬件要求 - CPU：4核以上 - 内存：8GB以上 - 硬盘：50GB可用空间 ### 软件要求 - JDK 11+ - MySQL 8.0+ - Redis 6.0+ - Git 2.0+ ## 风险分析 ### 高风险接口 1. 认证相关接口（登录、注册、Token刷新） 2. 支付/交易接口 3. 权限管理接口 ### 中风险接口 1. 核心业务数据操作 2. 第三方服务集成 3. 文件上传下载 ### 低风险接口 1. 查询统计接口 2. 只读数据接口 3. 静态资源配置 ## 总结 ### 测试点统计 - **参数校验**：XXX个 - **业务逻辑**：XXX个 - **响应验证**：XXX个 - **安全测试**：XXX个 - **性能测试**：XXX个 - **总计**：XXXX个测试点 ### 建议 1. 建立测试用例管理系统 2. 实施自动化测试回归 3. 定期进行安全扫描 4. 监控生产环境性能指标 5. 持续优化测试策略 --- **文档生成日期**：{date} **生成工具**：api-test-create v{version} **下次评审**：建议每月评审一次 ``` ## 参考资源 | 文档 | 用途 | |------|------| | `references/test-case-design.md` | 详细的测试用例设计方法和代码示例 | | `references/common-pitfalls.md` | 完整的140点API测试陷阱清单 | | `examples/openapi-example.yaml` | OpenAPI格式示例 | | `examples/simple-example.md` | 简化定义格式示例 |

path: QUICKSTART.md
content: # API测试分析文档生成器 - 快速开始

## 安装

### 方式1：使用pip安装依赖（推荐）

```bash
cd d:/code/autotestplatformnew/.codebuddy/skills/api-test-create
pip install -r requirements.txt
```

### 方式2：无需安装（基础功能）

如果只需要基本功能（不支持YAML格式），可以直接使用，无需安装任何依赖。

## 快速使用

### 步骤1：准备接口定义

#### 选项A：OpenAPI/Swagger格式（推荐）

创建文件 `api.yaml`：

```yaml
openapi: 3.0.0
info:
  title: 用户管理API
  version: 1.0.0
paths:
  /api/users:
    post:
      summary: 创建用户
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
                - username
                - password
              properties:
                username:
                  type: string
                  minLength: 3
                  maxLength: 20
                password:
                  type: string
                  minLength: 6
                  maxLength: 20
                email:
                  type: string
                  format: email
      responses:
        '200':
          description: 成功
```

#### 选项B：简化定义格式

创建文件 `api-simple.md`：

```markdown
接口名称: 创建用户
接口路径: POST /api/users
请求参数:
  - username: string, 必填, 3-20字符
  - [REDACTED_SECRET], 必填, 6-20字符
  - email: string, 可选, 邮箱格式
业务规则:
  - 用户名必须唯一
  - 邮箱必须唯一
```

### 步骤2：生成测试分析文档

#### 生成单个接口的测试分析

```bash
cd d:/code/autotestplatformnew/.codebuddy/skills/api-test-create/scripts

# 使用OpenAPI格式
python generate-checklist.py --input api.yaml --output test-analysis.md

# 使用简化格式
python generate-checklist.py --input api-simple.md --format simple --output test-analysis.md
```

#### 批量生成（多个接口）

如果你有包含多个接口的OpenAPI文件：

```bash
python generate-checklist.py --input full-api-spec.yaml --output complete-test-analysis.md
```

### 步骤3：查看生成的文档

生成的 `test-analysis.md` 文件将包含：

```markdown
# 用户管理API - API测试分析文档

**生成日期**：2025-03-26 08:30:00
**文档版本**：v1.0

## 详细测试分析

### 创建用户

#### 基本信息
- **接口路径**：POST /api/users
- **接口描述**：创建用户
- **认证**：否

#### 请求参数分析

##### username (string, 必填)
**约束条件**：
- 最小长度：3
- 最大长度：20

**参数校验测试点分析**：

| 测试场景 | 测试值说明 | 预期结果 | 优先级 | 测试目的 |
|----------|------------|----------|--------|----------|
| 正常值-最小长度 | aaa | 成功 | P1 | 验证下边界 |
| 正常值-典型值 | abcde | 成功 | P0 | 验证典型场景 |
| 正常值-最大长度 | a*20 | 成功 | P1 | 验证上边界 |
| 异常值-小于最小长度 | aa | 参数错误 | P1 | 验证越下界 |
| 异常值-超过最大长度 | a*21 | 参数错误 | P1 | 验证越上界 |
| 异常值-null | null | 参数错误 | P0 | 验证必填约束 |
| 安全-SQL注入 | ' OR '1'='1 | 参数错误 | P0 | 验证SQL注入防护 |
| 安全-XSS攻击 | <script>alert(1)</script> | 参数错误 | P0 | 验证XSS防护 |

**风险分析**：🔴 高风险

##### password (string, 必填)
...

#### 业务逻辑测试点分析

| 测试场景 | 前置条件 | 操作步骤 | 预期结果 | 优先级 | 测试目的 |
|----------|----------|----------|----------|--------|----------|
| 正常业务流程 | 数据准备完成 | 执行业务操作 | 业务成功 | P0 | 验证核心功能 |
| 用户名重复 | 用户名已存在 | 创建相同用户 | 业务错误（已存在） | P0 | 验证唯一性约束 |

#### 响应验证测试点分析

**成功响应（2xx）验证**：

| 验证项 | 验证内容 | 优先级 | 验证方法 |
|--------|----------|--------|----------|
| 响应结构 | 包含code, message, data字段 | P0 | 检查JSON结构 |
| 状态码 | 与业务结果匹配（200/201） | P0 | 检查HTTP状态码 |

#### 安全测试点分析

**认证安全**：

| 测试场景 | 测试操作 | 预期结果 | 风险等级 | 测试目的 |
|----------|----------|----------|----------|----------|
| 未认证访问 | 不携带Token调用接口 | 返回401 Unauthorized | 🔴 高 | 验证认证拦截 |
| Token过期 | 使用过期Token | 返回401 | 🔴 高 | 验证Token过期处理 |

#### 性能测试点分析

**响应时间要求**：
- P0接口：< 200ms (95分位)
- P1接口：< 500ms (95分位)

**压力测试场景**：

| 场景 | 并发数 | 持续时间 | 预期结果 | 关注点 |
|------|--------|----------|----------|--------|
| 基准测试 | 1 | 10分钟 | 响应稳定 | 基准响应时间 |
| 负载测试 | 10 | 30分钟 | 成功率>99.9% | 系统负载 |
```

## 命令行参数

### 基本用法

```bash
python generate-checklist.py --input <输入文件> --output <输出文件>
```

### 参数说明

| 参数 | 简写 | 说明 | 示例 |
|------|------|------|------|
| --input | -i | 输入文件（必需） | --input api.yaml |
| --output | -o | 输出文件 | --output analysis.md |
| --format | -f | 输入格式：openapi/simple | --format simple |
| --config | -c | 配置文件 | --config config.json |
| --api-name | -n | API名称 | --api-name "用户管理API" |

### 示例

```bash
# 基础用法
python generate-checklist.py -i api.yaml -o analysis.md

# 使用简化格式
python generate-checklist.py -i simple.md -f simple -o analysis.md

# 指定API名称
python generate-checklist.py -i api.yaml -n "订单系统API" -o order-test-analysis.md

# 不指定输出（打印到控制台）
python generate-checklist.py -i api.yaml
```

## 使用场景

### 场景1：为新接口设计测试方案

当你开发新接口时：

1. 编写接口定义（OpenAPI或简化格式）
2. 运行本工具生成测试分析文档
3. 根据文档评审测试点是否完整
4. 补充遗漏的测试场景
5. 将文档作为测试设计依据

### 场景2：评审现有接口测试覆盖

当你需要评审现有接口时：

1. 从代码提取接口定义
2. 运行本工具生成测试分析文档
3. 对比现有测试用例
4. 识别遗漏的测试点
5. 完善测试用例集

### 场景3：生成测试方案文档

当你需要输出测试方案时：

1. 准备完整接口定义
2. 运行本工具生成测试分析文档
3. 补充业务背景和风险分析
4. 作为测试方案交付物
5. 与团队评审确认

## 输出说明

### 文档结构

生成的Markdown文档包含：

1. **文档信息**：生成日期、版本
2. **接口清单**：所有接口的概览
3. **详细测试分析**：
   - 接口基本信息
   - 请求参数分析（每个参数）
   - 业务逻辑测试点
   - 响应验证测试点
   - 安全测试点
   - 性能测试点
4. **测试执行建议**：执行顺序、优先级
5. **风险分析**：高风险接口识别

### 优先级说明

- **P0（Critical）**：核心功能，必须测试
- **P1（High）**：重要功能，建议测试
- **P2（Medium）**：一般功能，选择测试
- **P3（Low）**：次要功能，可延后测试

## 高级配置

### 自定义优先级规则

创建 `config.json`：

```json
{
  "priority_rules": {
    "required_missing": "P0",
    "sql_injection": "P0",
    "xss": "P0",
    "authorization": "P0",
    "boundary_normal": "P1",
    "boundary_invalid": "P1",
    "optional": "P2"
  }
}
```

使用配置：

```bash
python generate-checklist.py -i api.yaml -c config.json -o analysis.md
```

## 最佳实践

### 1. 接口定义要清晰
- 明确参数类型、约束、必填项
- 添加详细的描述信息
- 包含业务规则说明

### 2. 定期更新分析文档
- 接口变更后重新生成
- 补充遗漏的测试点
- 更新风险分析

### 3. 结合团队评审
- 生成文档后团队评审
- 补充业务特定场景
- 确认测试优先级

### 4. 作为测试依据
- 基于文档设计测试用例
- 确保测试点全覆盖
- 跟踪测试执行情况

## 常见问题

### Q1: 支持哪些输入格式？

**A**: 支持OpenAPI/Swagger（JSON/YAML）和简化定义格式（Markdown）。

### Q2: 是否需要安装依赖？

**A**: 基础功能无需安装，如需支持YAML格式，需安装PyYAML。

### Q3: 如何生成多个接口的测试分析？

**A**: 在OpenAPI文件中定义所有接口，工具会生成完整的测试分析文档。

### Q4: 如何自定义测试点？

**A**: 当前版本不支持自定义测试点，可以手动编辑生成的文档进行补充。

### Q5: 文档生成后如何使用？

**A**: 作为测试设计依据，评审测试覆盖，指导测试执行，补充到测试方案中。

## 技术支持

如遇到问题：

1. 查看日志输出
2. 检查输入文件格式
3. 验证参数配置
4. 参考examples目录示例

## 版本历史

| 版本 | 日期 | 变更内容 |
|------|------|----------|
| v0.5.0 | 2025-03-26 | 简化功能，专注测试分析文档生成 |
| v0.4.1 | 2025-03-26 | 完整测试用例生成 |

---

**说明**：本工具专注于生成详细的API测试分析文档，帮助测试人员设计全面的测试方案。生成的文档需要结合业务实际进行评审和补充。


path: README.md
content: # API测试生成器

**版本**: 0.4.1
**类别**: 测试工具
**标签**: api, testing, openapi, swagger, create, automation

## 简介

API测试检查单生成器是一个根据接口规格自动生成全面测试点的工具。输入接口文档（支持OpenAPI/Swagger、简化定义或自然语言描述），自动输出结构化的测试用例清单，覆盖参数校验、业务逻辑、响应验证和常见陷阱。

## 特性

- 🤖 **智能解析**: 支持OpenAPI/Swagger、YAML/JSON、自然语言输入
- 📋 **全面覆盖**: 自动生成6大类测试点（参数、业务、响应、安全、性能、兼容性）
- 🎯 **优先级标注**: 测试点按P0/P1/P2分级
- ⚠️ **高频陷阱**: 内置100个高频易错点自动对照
- 📊 **统计报告**: 自动生成测试点数量统计

## 目录结构

```
api-test-checklist/
├── README.md                    # 本说明文档
├── SKILL.md                     # 主技能文件（Claude使用）
├── _meta.json                   # 元数据
├── scripts/                     # 可执行脚本
│   ├── generate-checklist.py    # 核心生成器
│   ├── validate-openapi.py      # OpenAPI验证工具
│   └── utils.py                 # 工具函数
├── references/                  # 参考文档
│   ├── test-case-design.md      # 测试用例设计方法
│   └── common-pitfalls.md       # 100个高频易错点
└── examples/                    # 示例
    ├── openapi-example.yaml     # OpenAPI示例
    └── simple-example.md        # 简化定义示例
```

## 快速开始

### 方式1：使用Claude Skill

直接告诉Claude你的接口定义：

```
我有以下接口，请生成测试检查单：
POST /api/users
参数：
  - username: string, 必填, 3-20字符
  - email: string, 必填, 邮箱格式
```

### 方式2：使用脚本生成

```bash
# 安装依赖
pip install -r requirements.txt

# 生成测试清单
python scripts/generate-checklist.py \
  --input examples/openapi-example.yaml \
  --output output/checklist.md

# 支持多种格式
python scripts/generate-checklist.py \
  --input "接口: POST /api/login 参数: username(string,必填) password(string,必填)" \
  --format text
```

### 方式3：编程调用

```python
from scripts.generate_checklist import APITestGenerator

# 初始化生成器
generator = APITestGenerator()

# 解析OpenAPI
api_spec = """
openapi: 3.0.0
paths:
  /api/users:
    post:
      summary: 创建用户
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                username:
                  type: string
                  minLength: 3
                  maxLength: 20
"""

# 生成测试清单
checklist = generator.generate_from_openapi(api_spec)
print(checklist)
```

## 输入格式支持

### 1. OpenAPI/Swagger

支持OpenAPI 3.0和Swagger 2.0规范。

**示例**: `examples/openapi-example.yaml`

```yaml
openapi: 3.0.0
info:
  title: 用户管理API
  version: 1.0.0
paths:
  /api/users:
    post:
      summary: 创建用户
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
                - username
                - email
              properties:
                username:
                  type: string
                  minLength: 3
                  maxLength: 20
                email:
                  type: string
                  format: email
```

### 2. 简化接口定义

```
接口名称: 创建用户
接口路径: POST /api/users
请求参数:
  - username: string, 必填, 3-20字符
  - email: string, 必填, 邮箱格式
  - age: integer, 可选, 0-150
返回字段:
  - id: integer
  - username: string
  - email: string
业务规则:
  - 用户名不能重复
  - 邮箱不能重复
```

### 3. 自然语言描述

```
登录接口：
- 路径：POST /api/auth/login
- 参数：用户名（必填，手机号或邮箱）、密码（必填，6-20位）
- 返回：token、用户信息
- 规则：密码错误5次锁定账号30分钟
```

## 输出格式

生成结构化的Markdown格式测试清单：

```markdown
## 接口：用户注册

### 基本信息
- 接口路径：POST /api/users/register
- 接口描述：用户注册接口

### 参数校验测试点

#### 1. username (string, 必填, 3-20字符)
| 测试场景 | 测试值 | 预期结果 | 优先级 |
|----------|--------|----------|--------|
| 正常值 | "testuser" | 成功 | P0 |
| 边界值-最小 | "abc" | 成功 | P1 |
| 边界值-最大 | "a"*20 | 成功 | P1 |
| 空值 | null/"" | 参数错误 | P0 |
| 特殊字符 | "<script>" | 参数错误 | P1 |

### 业务逻辑测试点
| 测试场景 | 前置条件 | 操作 | 预期结果 | 优先级 |
|----------|----------|------|----------|--------|
| 正常注册 | 无 | 提交有效数据 | 注册成功 | P0 |
| 用户名重复 | 用户已存在 | 相同用户名注册 | 返回已存在 | P0 |

### 安全测试点
| 测试场景 | 测试值 | 预期结果 | 优先级 |
|----------|------------|-----------------|----------|
| SQL注入 | "admin'--" | 参数错误 | P0 |

### 统计
- 参数校验：25个测试点
- 业务逻辑：6个测试点
- **总计：31个测试点**
```

## 测试点覆盖范围

### 1. 参数校验（自动生成）

| 参数类型 | 测试场景 |
|----------|----------|
| string | 长度边界、特殊字符、SQL注入、XSS、Unicode、格式校验 |
| integer | 取值范围、边界值、零值、负数、溢出、类型转换 |
| number | 精度、科学计数法、范围 |
| enum | 所有枚举值、无效值、大小写、null |
| boolean | true/false、字符串转换、数字转换 |
| array | 空数组、元素数量、重复元素、无效元素 |
| object | 完整对象、缺少必填、额外字段 |
| datetime | 有效日期、无效日期、格式、时区、闰年 |

### 2. 业务逻辑（按规则生成）

- 存在性校验（数据存在/不存在/已删除）
- 唯一性校验（重复数据）
- 状态转换校验（合法/非法转换）
- 权限校验（有权限/无权限/未登录）
- 关联校验（外键存在性）
- 数量限制（上限/下限）

### 3. 响应校验

- 结构完整性（code, message, data）
- 字段类型正确性
- 分页信息准确性
- 空结果处理（返回[]或null）

### 4. 安全测试

- SQL注入攻击
- XSS跨站脚本
- 认证绕过
- 越权访问
- 暴力破解

### 5. 性能测试建议

- 响应时间阈值
- 并发访问测试
- 大页码查询
- 批量操作限制

### 6. 兼容性测试

- 不同浏览器/客户端
- 不同环境（测试/生产）
- 不同版本共存

## 140个高频易错点

内置140个高频易错点自动对照，覆盖7大维度：

1. **请求层规范**（15项）：请求方法、请求头、协议、超时、编码
2. **参数处理**（30项）：必选/可选参数、格式类型、长度边界
3. **响应结果**（20项）：状态码、字段完整性、业务数据正确性
4. **业务逻辑**（15项）：幂等性、权限、状态流转、关联数据
5. **性能并发**（10项）：高并发、响应时间、资源占用、缓存
6. **安全兼容**（10项）：注入攻击、敏感数据、跨平台兼容
7. **补充测试项**（40项）：
   - **通用信息校验**（10项）：URL、请求方法、请求头、接口鉴权
   - **接口参数详细校验**（18项）：必填、选填、长度、类型、有效性、唯一性、关联项
   - **其他补充项**（12项）：幂等性、弱网环境、分布式、接口风格、敏感信息加密

详细清单见 `references/common-pitfalls.md`

## 进阶功能

### 自定义规则

创建 `config.json` 自定义测试规则：

```json
{
  "priority_rules": {
    "min_length": "P1",
    "sql_injection": "P0",
    "xss": "P0"
  },
  "custom_validators": {
    "phone_number": "^1[3-9]\\d{9}$",
    "id_card": "^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$"
  }
}
```

### 批量生成

```bash
# 批量处理多个接口
python scripts/generate-checklist.py \
  --input ./apis/*.yaml \
  --output ./output/ \
  --batch

# 生成测试代码
python scripts/generate-checklist.py \
  --input api-spec.yaml \
  --with-test-code \
  --framework pytest
```

## 开发与扩展

### 添加新参数类型

编辑 `scripts/utils.py`：

```python
# 在PARAM_TYPE_HANDLERS中添加新的处理器
def handle_custom_type(param_name, constraints):
    return [
        {"scenario": "正常值", "value": "valid_value", "expected": "success", "priority": "P0"},
        # ... 更多测试点
    ]
```

### 添加自定义业务规则

编辑 `scripts/generate-checklist.py`：

```python
# 在BUSINESS_RULE_PATTERNS中添加新规则
"custom_rule": {
    "pattern": r"必须包含(\\w+)",
    "generator": generate_custom_rule_tests
}
```

## 测试

```bash
# 运行单元测试
python -m pytest tests/

# 测试覆盖率
pytest --cov=scripts tests/

# 集成测试
python tests/integration_test.py
```

## 常见问题

### Q: 如何处理非标准的接口定义？
A: 使用 `--format text` 参数，提供自然语言描述

### Q: 如何自定义测试优先级？
A: 编辑 `config.json` 修改priority_rules

### Q: 支持哪些OpenAPI版本？
A: 支持OpenAPI 3.0和Swagger 2.0

### Q: 生成的测试点太多怎么办？
A: 使用 `--priority P0,P1` 参数只生成高优先级测试点

## 贡献

欢迎提交PR和Issue！

## 许可证

MIT License

## 更新日志

### v0.3.0 (2026-03-25)
- ✅ 添加可执行workflow脚本
- ✅ 统一使用中文文档
- ✅ 完善元数据信息
- ✅ 添加README.md
- ✅ 完善错误处理示例
- ✅ 添加单元测试

### v0.2.0 (2026-03-25)
- 添加100个高频易错点
- 优化输出格式
- 添加统计报告

### v0.1.0 (2026-03-25)
- 初始版本
- 基础测试点生成
- 支持OpenAPI/Swagger


path: README_EN.md
content: # API Test Create

**Version**: 0.4.1
**Category**: Testing Tool
**Tags**: api, testing, openapi, swagger, create, automation

## Overview

API Test Create is a tool that automatically generates comprehensive API test cases from interface specifications. It accepts API documentation (supporting OpenAPI/Swagger, simplified definitions, or natural language descriptions) and outputs structured test case checklists covering parameter validation, business logic, response verification, and common pitfalls.

## Features

- 🤖 **Smart Parsing**: Supports OpenAPI/Swagger, YAML/JSON, and natural language input
- 📋 **Comprehensive Coverage**: Automatically generates 7 categories of test points (Parameter, Business Logic, Response, Security, Performance, Compatibility, and Supplementary Tests)
- 🎯 **Priority Labeling**: Test points categorized as P0/P1/P2 priority levels
- ⚠️ **High-Frequency Pitfalls**: Built-in 140 common API testing pitfalls for automatic cross-checking
- 📊 **Statistical Reports**: Automatically generates test point quantity statistics

## Directory Structure

```
api-test-checklist/
├── README.md                    # Chinese documentation
├── README_EN.md                 # English documentation (this file)
├── QUICKSTART.md               # Quick start guide
├── SKILL.md                     # Main skill file (for Claude)
├── _meta.json                   # Metadata
├── requirements.txt            # Dependencies
├── scripts/                     # Executable scripts
│   ├── generate-checklist.py    # Core generator
│   └── utils.py                 # Utility functions
├── examples/                    # Examples
│   ├── openapi-example.yaml     # OpenAPI example
│   └── simple-example.md        # Simplified definition example
├── references/                  # Reference documentation
│   ├── test-case-design.md      # Test case design methods
│   └── common-pitfalls.md       # 140 common pitfalls
└── tests/                       # Unit tests
    └── test_generator.py        # Generator tests
```

## Quick Start

### Method 1: Using Claude Skill (Recommended)

Simply tell Claude your interface definition:

```
I have the following API, please generate a test checklist:

Interface Name: User Login
Endpoint: POST /api/users/login
Parameters:
  - username: string, required, 3-20 characters
  - [REDACTED_SECRET], required, 6-20 characters
Response:
  - [REDACTED_SECRET]
  - user: object
```

### Method 2: Using Script

#### Generate from OpenAPI/Swagger

```bash
python scripts/generate-checklist.py \
  --input examples/openapi-example.yaml \
  --format openapi \
  --output output/checklist.md
```

#### Generate from Simplified Definition

```bash
python scripts/generate-checklist.py \
  --input examples/simple-example.md \
  --format simple \
  --output output/checklist.md
```

#### Generate from String

```bash
python scripts/generate-checklist.py \
  --input "Interface: POST /api/login
Parameters:
  - username: string, required
  - [REDACTED_SECRET], required
Response:
  - [REDACTED_SECRET]" \
  --format simple
```

### Method 3: Programmatic Usage

```python
from scripts.generate_checklist import APITestGenerator

# Initialize generator
generator = APITestGenerator()

# Generate from OpenAPI
openapi_spec = """
{
  "openapi": "3.0.0",
  "info": {"title": "Test API", "version": "1.0.0"},
  "paths": {
    "/test": {
      "post": {
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {"type": "string", "minLength": 3, "maxLength": 20}
                }
              }
            }
          }
        }
      }
    }
  }
}
"""

checklist = generator.generate_from_openapi(openapi_spec, "Test API")
print(checklist)
```

## Input Formats

### 1. OpenAPI/Swagger (Recommended)

Supports OpenAPI 3.0 and Swagger 2.0 specifications.

**Example**: `examples/openapi-example.yaml`

### 2. Simplified Interface Definition

**Format**:

```
Interface Name: [Name]
Endpoint: [METHOD] [Path]
Parameters:
  - [param_name]: [type], [required/optional], [constraints], [description]
Response Fields:
  - [field_name]: [type]
Business Rules:
  - [rule_description]
```

**Example**: `examples/simple-example.md`

### 3. Natural Language Description

Describe the interface information directly, Claude will intelligently parse it.

## Output Example

Generates structured Markdown format:

```markdown
## API: User Registration

### Basic Information
- Endpoint: POST /api/users/register
- Description: User registration endpoint

### Parameter Validation Test Points

#### username (string, required, 3-20 characters)
| Test Scenario | Test Value | Expected Result | Priority |
|---------------|------------|-----------------|----------|
| Normal value | "testuser" | Success | P0 |
| Boundary - min length | "abc" | Success | P1 |
| Boundary - max length | "a"*20 | Success | P1 |
| Empty value | null/"" | Parameter error | P0 |
| Special characters | "<script>alert(1)</script>" | Parameter error | P1 |
| SQL injection | "admin'--" | Parameter error | P1 |

### Business Logic Test Points
| Test Scenario | Precondition | Action | Expected Result | Priority |
|---------------|--------------|--------|-----------------|----------|
| Normal registration | None | Submit valid data | Registration success, return token | P0 |
| Duplicate username | User "testuser" exists | Register with same username | Return username already exists | P0 |

### Response Verification Test Points
| Item | Verification | Priority |
|------|--------------|----------|
| Response structure | Contains code, message, data | P0 |
| data.id | Returns user ID (integer) | P0 |
| data.token | Returns valid JWT token | P0 |

### Security Test Points
| Test Scenario | Test Value | Expected Result | Priority |
|---------------|------------|-----------------|----------|
| SQL injection | "' OR '1'='1" | Parameter error | P0 |
| XSS attack | "<script>alert(1)</script>" | Parameter error | P0 |

### Statistics
- Parameter validation: 25 test points
- Business logic: 6 test points
- Response verification: 6 test points
- Security tests: 2 test points
- **Total: 39 test points**
```

## Test Coverage

### 1. Parameter Validation (Auto-generated)

| Parameter Type | Test Scenarios |
|----------------|----------------|
| string | Length boundaries, special chars, SQL injection, XSS, Unicode, format validation |
| integer | Value range, boundary values, zero, negative, overflow, type conversion |
| number | Precision, scientific notation, range |
| enum | All valid values, invalid values, case sensitivity, null |
| boolean | true/false, string conversion, numeric conversion |
| array | Empty array, element count, duplicate elements, invalid elements |
| object | Complete object, missing required fields, extra fields |
| datetime | Valid dates, invalid dates, format, timezone, leap year |

### 2. Business Logic (Rule-based)

- Existence validation (data exists/not exists/deleted)
- Uniqueness validation (duplicate data)
- State transition validation (valid/invalid transitions)
- Permission validation (authorized/unauthorized/not logged in)
- Association validation (foreign key existence)
- Quantity limits (upper/lower bounds)

### 3. Response Verification

- Structure completeness (code, message, data)
- Field type correctness
- Pagination information accuracy
- Empty result handling (returns [] or null)

### 4. Security Testing

- SQL injection attacks
- XSS cross-site scripting
- Authentication bypass
- Unauthorized access
- Brute force attacks

### 5. Performance Testing Suggestions

- Response time thresholds
- Concurrent access testing
- Large page number queries
- Batch operation limits

### 6. Compatibility Testing

- Different browsers/clients
- Different environments (test/production)
- Different version coexistence

### 7. Supplementary Tests (40 items)

#### 7.1 General Information Validation (10 items)
- URL correctness/error handling
- HTTP method correctness/errors
- Request header correctness/errors
- Interface authentication (correct, missing, wrong, expired)

#### 7.2 Detailed Parameter Validation (18 items)
- Required fields (complete, missing, null, empty string)
- Optional fields (none, partial)
- Length (exceed max, below min, equal to max)
- Data types (correct, wrong)
- Validity (within range, outside range)
- Uniqueness (unique, duplicate)
- Association (mutually exclusive, dependent)

#### 7.3 Other Supplementary Items (12 items)
- Idempotency (repeat submission, lottery, order modification)
- Weak network environment (network interruption, payment scenarios)
- Distributed systems (data synchronization, consistency)
- Interface style (RESTful compliance)
- Sensitive information (transmission encryption, log desensitization, storage encryption)

## 140 Common Pitfalls

Built-in 140 common pitfalls for automatic cross-checking, covering 7 dimensions:

1. **Request Layer Specification** (15 items)
2. **Parameter Processing** (30 items)
3. **Response Results** (20 items)
4. **Business Logic** (15 items)
5. **Performance & Concurrency** (10 items)
6. **Security & Compatibility** (10 items)
7. **Supplementary Tests** (40 items) - Includes 40 detailed test items provided by users

See `references/common-pitfalls.md` for detailed list.

## Configuration

Create `config.json` for customization:

```bash
# Create config.json based on your needs
{
  "priority_rules": {
    "required_missing": "P0",
    "sql_injection": "P0"
  }
}
```

### Configuration Options

- `priority_rules`: Test priority rules
- `custom_validators`: Custom validators
- `test_data_generators`: Test data generation rules
- `security_test_cases`: Security test cases

## Advanced Features

### Batch Generation

```bash
# Batch process all YAML files in directory
for file in apis/*.yaml; do
  python scripts/generate-checklist.py \
    --input "$file" \
    --output "output/$(basename "$file" .yaml).md"
done
```

### Custom Rules

Edit `config.json`:

```json
{
  "custom_validators": {
    "phone_number": {
      "pattern": "^1[3-9]\\d{9}$",
      "error_message": "Invalid phone number format"
    }
  }
}
```

## Testing

```bash
# Run unit tests
pytest tests/

# Test coverage
pytest --cov=scripts tests/

# Integration tests
python tests/integration_test.py
```

## FAQ

### Q: How to handle non-standard interface definitions?
A: Use `--format text` parameter and provide natural language description

### Q: How to customize test priorities?
A: Edit `config.json` and modify `priority_rules`

### Q: Which OpenAPI versions are supported?
A: OpenAPI 3.0 and Swagger 2.0

### Q: What if too many test points are generated?
A: Use `--priority P0,P1` parameter to generate only high-priority test points

### Q: How to run tests?
A: `pytest tests/`

## Changelog

### v0.4.1 (2026-03-25)
- ✅ Added 40 supplementary test items
- ✅ Added general information validation tests
- ✅ Added detailed parameter validation tests
- ✅ Added idempotency, weak network, distributed system tests
- ✅ Added RESTful style and sensitive information encryption tests
- ✅ Updated all documentation to reflect 140 test points

### v0.4.0 (2026-03-25)
- ✅ Added executable workflow scripts
- ✅ Unified Chinese documentation
- ✅ Enhanced metadata
- ✅ Added README.md and QUICKSTART.md
- ✅ Added unit tests (pytest)
- ✅ Added configuration examples
- ✅ Added OpenAPI and simplified definition examples

### v0.3.0 (2026-03-25)
- Optimized document structure
- Added detailed workflow

### v0.2.0 (2026-03-25)
- Added 100 common pitfalls

### v0.1.0 (2026-03-25)
- Initial version

## Contributing

Welcome to submit Issues and PRs!

## License

MIT License


path: requirements.txt
content: # API测试分析文档生成器依赖

# YAML解析（可选，用于OpenAPI YAML格式）
PyYAML>=6.0

# 日志和调试（内置模块，无需额外安装）
# logging - Python内置
# datetime - Python内置


path: _meta.json
content: {
  "version": "0.5.0",
  "name": "api-test-create",
  "display_name": "API测试分析生成器",
  "description": "根据接口规格生成详细的API测试分析文档，涵盖参数校验、业务逻辑、响应验证和安全测试分析点，内置140个常见测试陷阱检查",
  "author": "AutoTest Platform",
  "category": "testing",
  "tags": ["api", "testing", "analysis", "openapi", "swagger", "文档生成"],
  "input_formats": ["openapi", "swagger", "yaml", "json", "markdown", "text"],
  "output_formats": ["markdown"],
  "language": "zh-CN",
  "requires": ["python>=3.8"],
  "license": "MIT"
}


path: tests/test_generator.py
content: #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
测试：API测试生成器
"""

import pytest
import sys
import os
from pathlib import Path

# 添加脚本目录到路径
sys.path.insert(0, str(Path(__file__).parent.parent / "scripts"))

from generate_checklist import APITestGenerator


class TestAPITestGenerator:
    """测试APITestGenerator类"""

    @pytest.fixture
    def generator(self):
        """创建生成器实例"""
        return APITestGenerator()

    def test_init(self, generator):
        """测试初始化"""
        assert generator is not None
        assert isinstance(generator.config, dict)
        assert "priority_rules" in generator.config

    def test_generate_from_openapi_simple(self, generator):
        """测试从简单的OpenAPI生成"""
        openapi_spec = """
        {
            "openapi": "3.0.0",
            "info": {
                "title": "Test API",
                "version": "1.0.0"
            },
            "paths": {
                "/test": {
                    "post": {
                        "summary": "Test endpoint",
                        "requestBody": {
                            "content": {
                                "application/json": {
                                    "schema": {
                                        "type": "object",
                                        "properties": {
                                            "name": {
                                                "type": "string",
                                                "minLength": 3,
                                                "maxLength": 20
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        """

        result = generator.generate_from_openapi(openapi_spec, "Test API")
        assert "接口：Test API" in result
        assert "参数校验测试点" in result
        assert "name" in result

    def test_generate_string_tests(self, generator):
        """测试字符串参数测试生成"""
        spec = {
            "type": "string",
            "minLength": 3,
            "maxLength": 20
        }

        tests = generator._generate_param_tests("username", spec, True)
        assert len(tests) > 0

        # 检查是否包含关键测试场景
        scenarios = [test["scenario"] for test in tests]
        assert "正常值" in scenarios
        assert "边界值-最小长度" in scenarios
        assert "边界值-最大长度" in scenarios
        assert "SQL注入" in scenarios

    def test_generate_integer_tests(self, generator):
        """测试整数参数测试生成"""
        spec = {
            "type": "integer",
            "minimum": 0,
            "maximum": 100
        }

        tests = generator._generate_param_tests("age", spec, True)
        assert len(tests) > 0

        scenarios = [test["scenario"] for test in tests]
        assert "正常值" in scenarios
        assert "边界值-最小" in scenarios
        assert "边界值-最大" in scenarios

    def test_generate_business_logic_tests(self, generator):
        """测试业务逻辑测试生成"""
        spec = {
            "paths": {
                "/test": {
                    "post": {
                        "summary": "创建唯一数据",
                        "description": "数据必须唯一"
                    }
                }
            }
        }

        tests = generator._generate_business_logic_tests(spec)
        assert len(tests) > 0

        scenarios = [test["scenario"] for test in tests]
        assert any("唯一" in scenario for scenario in scenarios)

    def test_generate_security_tests(self, generator):
        """测试安全测试生成"""
        spec = {}
        tests = generator._generate_security_tests(spec)
        assert len(tests) > 0

        scenarios = [test["scenario"] for test in tests]
        assert any("SQL注入" in scenario for scenario in scenarios)
        assert any("XSS" in scenario for scenario in scenarios)

    def test_parse_simple_definition(self, generator):
        """测试简化定义解析"""
        simple_def = """
        接口名称: 测试接口
        接口路径: POST /api/test
        请求参数:
          - name: string, 必填, 3-20字符
          - age: integer, 可选, 0-150
        返回字段:
          - id: integer
          - name: string
        业务规则:
          - 名称不能重复
        """

        parsed = generator._parse_simple_definition(simple_def)
        assert parsed["name"] == "测试接口"
        assert parsed["path"] == "/api/test"
        assert parsed["method"] == "POST"
        assert len(parsed["parameters"]) == 2
        assert len(parsed["rules"]) == 1

    def test_parse_parameter_line(self, generator):
        """测试参数字符串解析"""
        # 测试字符串参数
        result = generator._parse_parameter_line("- username: string, 必填, 3-20字符")
        assert result is not None
        assert result["name"] == "username"
        assert result["type"] == "string"
        assert result["required"] is True
        assert result["minLength"] == 3
        assert result["maxLength"] == 20

        # 测试整数参数
        result = generator._parse_parameter_line("- age: integer, 可选, 0-150")
        assert result is not None
        assert result["name"] == "age"
        assert result["type"] == "integer"
        assert result["required"] is False

        # 测试枚举参数
        result = generator._parse_parameter_line("- status: enum, 可选, [active, inactive, pending]")
        assert result is not None
        assert result["name"] == "status"
        assert "enum" in result
        assert len(result["enum"]) == 3

    def test_convert_to_openapi(self, generator):
        """测试转换为OpenAPI格式"""
        parsed = {
            "name": "测试接口",
            "path": "/api/test",
            "method": "POST",
            "parameters": [
                {
                    "name": "username",
                    "type": "string",
                    "required": True,
                    "minLength": 3,
                    "maxLength": 20
                }
            ],
            "rules": []
        }

        openapi = generator._convert_to_openapi(parsed)
        assert "openapi" in openapi
        assert "paths" in openapi
        assert "/api/test" in openapi["paths"]

    def test_generate_markdown(self, generator):
        """测试Markdown生成"""
        api_info = {
            "name": "测试API",
            "path": "/api/test",
            "method": "POST",
            "description": "测试接口"
        }

        test_points = {
            "parameter_tests": [
                {
                    "param": "username",
                    "scenario": "正常值",
                    "value": "testuser",
                    "expected": "成功",
                    "priority": "P0"
                }
            ],
            "business_logic_tests": [
                {
                    "scenario": "正常流程",
                    "precondition": "无",
                    "action": "提交数据",
                    "expected": "成功",
                    "priority": "P0"
                }
            ],
            "response_tests": [
                {
                    "item": "结构",
                    "verification": "包含code, message, data",
                    "priority": "P0"
                }
            ],
            "security_tests": [
                {
                    "scenario": "SQL注入",
                    "value": "' OR '1'='1",
                    "expected": "参数错误",
                    "priority": "P0"
                }
            ]
        }

        markdown = generator._generate_markdown(api_info, test_points)
        assert "接口：测试API" in markdown
        assert "参数校验测试点" in markdown
        assert "业务逻辑测试点" in markdown
        assert "安全测试点" in markdown
        assert "总计" in markdown

    def test_generate_from_simple(self, generator):
        """测试从简化定义生成"""
        simple_def = """
        接口名称: 用户登录
        接口路径: POST /api/login
        请求参数:
          - username: string, 必填, 3-20字符
          - [REDACTED_SECRET], 必填, 6-20字符
        返回字段:
          - [REDACTED_SECRET]
        """

        result = generator.generate_from_simple(simple_def)
        assert "接口：用户登录" in result
        assert "username" in result
        assert "password" in result

    def test_error_handling(self, generator):
        """测试错误处理"""
        # 测试无效的OpenAPI
        with pytest.raises((ValueError, Exception)):
            generator.generate_from_openapi("invalid json")

        # 测试无效的简化定义
        with pytest.raises((ValueError, Exception)):
            generator.generate_from_simple("invalid format")


class TestUtils:
    """测试工具函数"""

    def test_generate_test_value(self):
        """测试生成测试值"""
        from utils import generate_test_value

        # 测试字符串
        value = generate_test_value("string", {"minLength": 3, "maxLength": 20})
        assert isinstance(value, str)
        assert len(value) >= 3
        assert len(value) <= 20

        # 测试整数
        value = generate_test_value("integer", {"minimum": 0, "maximum": 100})
        assert isinstance(value, int)
        assert value >= 0
        assert value <= 100

        # 测试布尔
        value = generate_test_value("boolean")
        assert isinstance(value, bool)

    def test_generate_invalid_value(self):
        """测试生成无效值"""
        from utils import generate_invalid_value

        # 测试字符串
        value = generate_invalid_value("string", {"minLength": 3})
        assert value == ""

        # 测试整数
        value = generate_invalid_value("integer", {"minimum": 0})
        assert value == -1

    def test_security_checks(self):
        """测试安全检测函数"""
        from utils import is_sql_injection, is_xss

        # SQL注入检测
        assert is_sql_injection("' OR '1'='1") is True
        assert is_sql_injection("admin'--") is True
        assert is_sql_injection("normal_user") is False

        # XSS检测
        assert is_xss("<script>alert(1)</script>") is True
        assert is_xss("<img src=x onerror=alert(1)>") is True
        assert is_xss("normal text") is False

    def test_format_validation(self):
        """测试格式验证"""
        from utils import validate_email, validate_phone, validate_uuid

        # 邮箱验证
        assert validate_email("[REDACTED_SECRET]") is True
        assert validate_email("invalid-email") is False

        # 手机号验证
        assert validate_phone("13800138000") is True
        assert validate_phone("12345678901") is False

        # UUID验证
        import uuid
        assert validate_uuid(str(uuid.uuid4())) is True
        assert validate_uuid("invalid-uuid") is False

    def test_calculate_boundary_values(self):
        """测试边界值计算"""
        from utils import calculate_boundary_values

        boundaries = calculate_boundary_values(0, 100)
        assert boundaries["minimum"] == 0
        assert boundaries["maximum"] == 100
        assert boundaries["just_below_minimum"] == -1
        assert boundaries["just_above_maximum"] == 101


if __name__ == "__main__":
    pytest.main([__file__, "-v"])


path: scripts/generate-checklist.py
content: #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
API测试分析文档生成器
根据接口规格自动生成详细的API测试分析文档
"""

import json
import yaml
import re
import sys
import argparse
from typing import Dict, List, Any, Optional, Union
from pathlib import Path
import logging
from datetime import datetime

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)


class APITestAnalyzer:
    """API测试分析文档生成器"""

    def __init__(self, config_path: Optional[str] = None):
        """
        初始化分析器

        Args:
            config_path: 配置文件路径
        """
        self.config = self._load_config(config_path)
        self.priority_rules = self.config.get('priority_rules', {})

    def _load_config(self, config_path: Optional[str] = None) -> Dict[str, Any]:
        """
        加载配置文件

        Args:
            config_path: 配置文件路径

        Returns:
            配置字典
        """
        default_config = {
            "priority_rules": {
                "required_missing": "P0",
                "sql_injection": "P0",
                "xss": "P0",
                "authorization": "P0",
                "boundary_normal": "P1",
                "boundary_invalid": "P1",
                "optional": "P2"
            }
        }

        if config_path and Path(config_path).exists():
            try:
                with open(config_path, 'r', encoding='utf-8') as f:
                    user_config = json.load(f)
                default_config.update(user_config)
                logger.info(f"加载配置文件: {config_path}")
            except Exception as e:
                logger.warning(f"加载配置文件失败: {e}，使用默认配置")

        return default_config

    def analyze_from_openapi(self, openapi_spec: Union[str, Dict[str, Any]],
                             api_name: Optional[str] = None) -> str:
        """
        从OpenAPI规范生成测试分析文档

        Args:
            openapi_spec: OpenAPI规范（字符串或字典）
            api_name: API名称

        Returns:
            Markdown格式的测试分析文档
        """
        try:
            if isinstance(openapi_spec, str):
                spec = self._parse_spec(openapi_spec)
            else:
                spec = openapi_spec

            return self._generate_analysis_markdown(spec, api_name)

        except Exception as e:
            logger.error(f"生成测试分析文档失败: {e}", exc_info=True)
            raise

    def analyze_from_simple(self, simple_def: str) -> str:
        """
        从简化定义生成测试分析文档

        Args:
            simple_def: 简化接口定义

        Returns:
            Markdown格式的测试分析文档
        """
        try:
            parsed = self._parse_simple_definition(simple_def)
            spec = self._convert_to_openapi(parsed)
            return self._generate_analysis_markdown(spec, parsed.get('name'))

        except Exception as e:
            logger.error(f"解析简化定义失败: {e}", exc_info=True)
            raise

    def _parse_spec(self, spec_str: str) -> Dict[str, Any]:
        """解析规范字符串"""
        spec_str = spec_str.strip()
        try:
            if spec_str.startswith('{'):
                return json.loads(spec_str)
            else:
                return yaml.safe_load(spec_str)
        except Exception as e:
            logger.error(f"规范解析失败: {e}")
            raise ValueError(f"无法解析规范: {e}")

    def _parse_simple_definition(self, simple_def: str) -> Dict[str, Any]:
        """解析简化定义"""
        parsed = {
            "name": "",
            "path": "",
            "method": "POST",
            "parameters": [],
            "responses": {},
            "rules": []
        }

        lines = simple_def.strip().split('\n')
        for line in lines:
            line = line.strip()
            if not line:
                continue

            if line.startswith('接口名称:') or line.startswith('API:'):
                parsed["name"] = line.split(':', 1)[1].strip()
            elif line.startswith('接口路径:') or line.startswith('端点:'):
                path_info = line.split(':', 1)[1].strip()
                match = re.match(r'(GET|POST|PUT|DELETE|PATCH)\s+(.+)', path_info, re.IGNORECASE)
                if match:
                    parsed["method"] = match.group(1).upper()
                    parsed["path"] = match.group(2)
                else:
                    parsed["path"] = path_info
            elif line.startswith('-') and ':' in line:
                param_info = self._parse_parameter_line(line)
                if param_info:
                    parsed["parameters"].append(param_info)
            elif line.startswith('-') and '不能' in line:
                parsed["rules"].append(line.strip('- ').strip())

        return parsed

    def _parse_parameter_line(self, line: str) -> Optional[Dict[str, Any]]:
        """解析参数字符串"""
        try:
            line = line.strip('- ').strip()
            if ':' not in line:
                return None

            name_part, def_part = line.split(':', 1)
            name = name_part.strip()
            definition = def_part.strip()

            param = {
                "name": name,
                "type": "string",
                "required": False,
                "description": definition
            }

            type_match = re.search(r'(string|integer|number|boolean|array|object)', definition, re.IGNORECASE)
            if type_match:
                param["type"] = type_match.group(1).lower()

            if '必填' in definition or 'required' in definition:
                param["required"] = True

            length_match = re.search(r'(\d+)\s*-\s*(\d+)\s*字符', definition)
            if length_match:
                param["minLength"] = int(length_match.group(1))
                param["maxLength"] = int(length_match.group(2))

            enum_match = re.search(r'\[([^\]]+)\]', definition)
            if enum_match:
                enum_values = enum_match.group(1).split(',')
                param["enum"] = [v.strip() for v in enum_values]

            return param

        except Exception as e:
            logger.warning(f"解析参数失败 '{line}': {e}")
            return None

    def _convert_to_openapi(self, parsed: Dict[str, Any]) -> Dict[str, Any]:
        """转换为OpenAPI格式"""
        spec = {
            "openapi": "3.0.0",
            "info": {
                "title": parsed.get("name", "API"),
                "version": "1.0.0"
            },
            "paths": {
                parsed.get("path", "/"): {
                    parsed.get("method", "POST").lower(): {
                        "summary": parsed.get("name", ""),
                        "requestBody": {
                            "content": {
                                "application/json": {
                                    "schema": {
                                        "type": "object",
                                        "required": [],
                                        "properties": {}
                                    }
                                }
                            }
                        },
                        "responses": {
                            "200": {
                                "description": "成功"
                            }
                        }
                    }
                }
            }
        }

        properties = spec["paths"][parsed["path"]][parsed["method"].lower()]["requestBody"]["content"]["application/json"]["schema"]["properties"]
        required = spec["paths"][parsed["path"]][parsed["method"].lower()]["requestBody"]["content"]["application/json"]["schema"]["required"]

        for param in parsed.get("parameters", []):
            properties[param["name"]] = {}
            if param["type"] == "string":
                properties[param["name"]]["type"] = "string"
                if "minLength" in param:
                    properties[param["name"]]["minLength"] = param["minLength"]
                if "maxLength" in param:
                    properties[param["name"]]["maxLength"] = param["maxLength"]
            elif param["type"] == "integer":
                properties[param["name"]]["type"] = "integer"

            if param.get("required"):
                required.append(param["name"])

        return spec

    def _generate_analysis_markdown(self, spec: Dict[str, Any], api_name: Optional[str] = None) -> str:
        """生成详细的测试分析文档"""
        lines = []

        # 文档标题
        api_title = api_name or spec.get("info", {}).get("title", "API接口")
        lines.append(f"# {api_title} - API测试分析文档")
        lines.append("")
        lines.append(f"**生成日期**：{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
        lines.append(f"**文档版本**：v1.0")
        lines.append("")

        # 接口清单
        paths = spec.get("paths", {})
        if len(paths) > 1:
            lines.append("## 接口清单")
            lines.append("")
            lines.append("| 序号 | 接口名称 | 路径 | 方法 | 测试点数 |")
            lines.append("|------|----------|------|------|----------|")

            for idx, (path, path_item) in enumerate(paths.items(), 1):
                for method, operation in path_item.items():
                    summary = operation.get("summary", "未命名接口")
                    lines.append(f"| {idx} | {summary} | {path} | {method.upper()} | 待计算 |")
            lines.append("")

        # 详细接口分析
        lines.append("## 详细测试分析")
        lines.append("")

        for path, path_item in paths.items():
            for method, operation in path_item.items():
                self._analyze_single_endpoint(lines, path, method, operation, spec)

        return "\n".join(lines)

    def _analyze_single_endpoint(self, lines: List[str], path: str, method: str, operation: Dict[str, Any], spec: Dict[str, Any]):
        """分析单个接口"""
        summary = operation.get("summary", "未命名接口")
        description = operation.get("description", "")

        lines.append(f"### {summary}")
        lines.append("")
        lines.append("#### 基本信息")
        lines.append(f"- **接口路径**：{method.upper()} {path}")
        if description:
            lines.append(f"- **接口描述**：{description}")
        lines.append("")

        # 请求参数分析
        self._analyze_request_params(lines, operation, spec)

        # 业务逻辑分析
        self._analyze_business_logic(lines, operation)

        # 响应验证分析
        self._analyze_response(lines, operation)

        # 安全测试分析
        self._analyze_security(lines)

        # 性能测试分析
        self._analyze_performance(lines)

        lines.append("---")
        lines.append("")

    def _analyze_request_params(self, lines: List[str], operation: Dict[str, Any], spec: Dict[str, Any]):
        """分析请求参数"""
        request_body = operation.get("requestBody", {})
        content = request_body.get("content", {})

        if not content:
            return

        lines.append("#### 请求参数分析")
        lines.append("")

        for content_type, schema_def in content.items():
            if content_type != "application/json":
                continue

            schema = schema_def.get("schema", {})
            properties = schema.get("properties", {})
            required_fields = schema.get("required", [])

            if not properties:
                continue

            for param_name, param_spec in properties.items():
                self._analyze_parameter(lines, param_name, param_spec, param_name in required_fields)

    def _analyze_parameter(self, lines: List[str], param_name: str, param_spec: Dict[str, Any], required: bool):
        """分析单个参数"""
        param_type = param_spec.get("type", "string")
        description = param_spec.get("description", "")

        lines.append(f"##### {param_name} ({param_type}, {'必填' if required else '可选'})")
        if description:
            lines.append(f"**参数描述**：{description}")
        lines.append("")

        # 参数约束
        constraints = []
        if "minLength" in param_spec:
            constraints.append(f"最小长度：{param_spec['minLength']}")
        if "maxLength" in param_spec:
            constraints.append(f"最大长度：{param_spec['maxLength']}")
        if "minimum" in param_spec:
            constraints.append(f"最小值：{param_spec['minimum']}")
        if "maximum" in param_spec:
            constraints.append(f"最大值：{param_spec['maximum']}")
        if "enum" in param_spec:
            constraints.append(f"枚举值：{param_spec['enum']}")
        if "pattern" in param_spec:
            constraints.append(f"正则表达式：{param_spec['pattern']}")

        if constraints:
            lines.append("**约束条件**：")
            for constraint in constraints:
                lines.append(f"- {constraint}")
            lines.append("")

        # 参数校验测试点
        lines.append("**参数校验测试点分析**：")
        lines.append("")
        lines.append("| 测试场景 | 测试值说明 | 预期结果 | 优先级 | 测试目的 |")
        lines.append("|----------|------------|----------|--------|----------|")

        test_points = self._get_param_test_points(param_name, param_spec, required)
        for point in test_points:
            lines.append(f"| {point['scenario']} | {point['test_value']} | {point['expected']} | {point['priority']} | {point['purpose']} |")

        lines.append("")

        # 风险分析
        risk_level = self._assess_param_risk(param_spec, required)
        lines.append(f"**风险分析**：{risk_level}")
        lines.append("")

    def _get_param_test_points(self, param_name: str, param_spec: Dict[str, Any], required: bool) -> List[Dict[str, Any]]:
        """获取参数测试点"""
        param_type = param_spec.get("type", "string")
        test_points = []

        if param_type == "string":
            test_points = self._get_string_test_points(param_spec, required)
        elif param_type == "integer":
            test_points = self._get_integer_test_points(param_spec, required)
        elif param_type == "number":
            test_points = self._get_number_test_points(param_spec, required)
        elif param_type == "boolean":
            test_points = self._get_boolean_test_points(param_spec, required)
        elif param_type == "array":
            test_points = self._get_array_test_points(param_spec, required)
        else:
            test_points = self._get_default_test_points(param_spec, required)

        return test_points

    def _get_string_test_points(self, param_spec: Dict[str, Any], required: bool) -> List[Dict[str, Any]]:
        """获取字符串类型测试点"""
        min_len = param_spec.get("minLength", 0)
        max_len = param_spec.get("maxLength", 100)
        enum_values = param_spec.get("enum", [])

        points = []

        if enum_values:
            # 枚举类型
            points.extend([
                {"scenario": "正常值-枚举值", "test_value": f"{enum_values[0]}", "expected": "成功", "priority": "P0", "purpose": "验证有效枚举值"},
                {"scenario": "异常值-非枚举值", "test_value": f"非枚举值", "expected": "参数错误", "priority": "P0", "purpose": "验证枚举约束"},
            ])
        else:
            # 普通字符串
            if min_len > 0:
                points.append({"scenario": "正常值-最小长度", "test_value": f"{'a' * min_len}", "expected": "成功", "priority": "P1", "purpose": "验证下边界"})
                points.append({"scenario": "正常值-典型值", "test_value": f"{'a' * min(min_len + 5, max_len)}", "expected": "成功", "priority": "P0", "purpose": "验证典型场景"})
            if max_len < 1000:
                points.append({"scenario": "正常值-最大长度", "test_value": f"{'a' * max_len}", "expected": "成功", "priority": "P1", "purpose": "验证上边界"})
                points.append({"scenario": "异常值-超过最大长度", "test_value": f"{'a' * (max_len + 1)}", "expected": "参数错误", "priority": "P1", "purpose": "验证越界处理"})

        if required:
            points.extend([
                {"scenario": "异常值-null", "test_value": "null", "expected": "参数错误", "priority": "P0", "purpose": "验证必填约束"},
                {"scenario": "异常值-空字符串", "test_value": '""', "expected": "参数错误", "priority": "P0", "purpose": "验证空值处理"},
            ])
        else:
            points.append({"scenario": "正常值-null（可选）", "test_value": "null", "expected": "成功", "priority": "P2", "purpose": "验证可选参数"})

        # 安全测试点
        points.extend([
            {"scenario": "安全-SQL注入", "test_value": "' OR '1'='1", "expected": "参数错误", "priority": "P0", "purpose": "验证SQL注入防护"},
            {"scenario": "安全-XSS攻击", "test_value": "<script>alert(1)</script>", "expected": "参数错误", "priority": "P0", "purpose": "验证XSS防护"},
            {"scenario": "安全-路径遍历", "test_value": "../../../etc/passwd", "expected": "参数错误", "priority": "P0", "purpose": "验证路径遍历防护"},
            {"scenario": "特殊字符", "test_value": "!@#$%^&*()", "expected": "成功或参数错误", "priority": "P1", "purpose": "验证特殊字符处理"},
        ])

        return points

    def _get_integer_test_points(self, param_spec: Dict[str, Any], required: bool) -> List[Dict[str, Any]]:
        """获取整数类型测试点"""
        min_val = param_spec.get("minimum", 0)
        max_val = param_spec.get("maximum", 100)

        points = [
            {"scenario": "正常值-最小值", "test_value": str(min_val), "expected": "成功", "priority": "P1", "purpose": "验证下边界"},
            {"scenario": "正常值-中间值", "test_value": str((min_val + max_val) // 2), "expected": "成功", "priority": "P0", "purpose": "验证典型场景"},
            {"scenario": "正常值-最大值", "test_value": str(max_val), "expected": "成功", "priority": "P1", "purpose": "验证上边界"},
            {"scenario": "异常值-小于最小值", "test_value": str(min_val - 1), "expected": "参数错误", "priority": "P1", "purpose": "验证越下界"},
            {"scenario": "异常值-大于最大值", "test_value": str(max_val + 1), "expected": "参数错误", "priority": "P1", "purpose": "验证越上界"},
            {"scenario": "异常值-小数", "test_value": "3.14", "expected": "参数错误", "priority": "P1", "purpose": "验证类型检查"},
            {"scenario": "异常值-字符串", "test_value": '"abc"', "expected": "参数错误", "priority": "P1", "purpose": "验证类型检查"},
        ]

        if required:
            points.append({"scenario": "异常值-null", "test_value": "null", "expected": "参数错误", "priority": "P0", "purpose": "验证必填约束"})
        else:
            points.append({"scenario": "正常值-null（可选）", "test_value": "null", "expected": "成功", "priority": "P2", "purpose": "验证可选参数"})

        return points

    def _get_number_test_points(self, param_spec: Dict[str, Any], required: bool) -> List[Dict[str, Any]]:
        """获取数字类型测试点"""
        return self._get_integer_test_points(param_spec, required)

    def _get_boolean_test_points(self, param_spec: Dict[str, Any], required: bool) -> List[Dict[str, Any]]:
        """获取布尔类型测试点"""
        points = [
            {"scenario": "正常值-true", "test_value": "true", "expected": "成功", "priority": "P0", "purpose": "验证true值"},
            {"scenario": "正常值-false", "test_value": "false", "expected": "成功", "priority": "P0", "purpose": "验证false值"},
            {"scenario": "异常值-字符串", "test_value": '"yes"', "expected": "参数错误", "priority": "P1", "purpose": "验证类型检查"},
            {"scenario": "异常值-整数", "test_value": "1", "expected": "参数错误", "priority": "P1", "purpose": "验证类型检查"},
        ]

        if required:
            points.append({"scenario": "异常值-null", "test_value": "null", "expected": "参数错误", "priority": "P0", "purpose": "验证必填约束"})

        return points

    def _get_array_test_points(self, param_spec: Dict[str, Any], required: bool) -> List[Dict[str, Any]]:
        """获取数组类型测试点"""
        points = [
            {"scenario": "正常值-空数组", "test_value": "[]", "expected": "成功", "priority": "P2", "purpose": "验证空数组"},
            {"scenario": "正常值-单元素", "test_value": "[1]", "expected": "成功", "priority": "P0", "purpose": "验证单元素"},
            {"scenario": "正常值-多元素", "test_value": "[1, 2, 3]", "expected": "成功", "priority": "P0", "purpose": "验证多元素"},
            {"scenario": "异常值-非数组", "test_value": "1", "expected": "参数错误", "priority": "P1", "purpose": "验证类型检查"},
            {"scenario": "异常值-字符串", "test_value": '"abc"', "expected": "参数错误", "priority": "P1", "purpose": "验证类型检查"},
        ]

        if required:
            points.append({"scenario": "异常值-null", "test_value": "null", "expected": "参数错误", "priority": "P0", "purpose": "验证必填约束"})

        return points

    def _get_default_test_points(self, param_spec: Dict[str, Any], required: bool) -> List[Dict[str, Any]]:
        """获取默认测试点"""
        return [
            {"scenario": "正常值", "test_value": "有效值", "expected": "成功", "priority": "P0", "purpose": "验证基本功能"},
            {"scenario": "异常值-null", "test_value": "null", "expected": "参数错误", "priority": "P0" if required else "P2", "purpose": "验证null处理"},
        ]

    def _assess_param_risk(self, param_spec: Dict[str, Any], required: bool) -> str:
        """评估参数风险等级"""
        risk_factors = []

        if required:
            risk_factors.append("必填参数")

        if param_spec.get("type") == "string":
            if not param_spec.get("pattern") and not param_spec.get("enum"):
                risk_factors.append("无格式验证")
            if param_spec.get("maxLength", 0) > 1000:
                risk_factors.append("长度过大")

        if len(risk_factors) == 0:
            return "🟢 低风险"
        elif len(risk_factors) <= 2:
            return "🟡 中风险"
        else:
            return "🔴 高风险"

    def _analyze_business_logic(self, lines: List[str], operation: Dict[str, Any]):
        """分析业务逻辑"""
        description = operation.get("description", "")
        summary = operation.get("summary", "")
        text = f"{summary} {description}"

        lines.append("#### 业务逻辑测试点分析")
        lines.append("")

        scenarios = []

        # 唯一性规则
        if "唯一" in text or "unique" in text.lower():
            scenarios.extend([
                {"name": "唯一性校验-首次创建", "precondition": "数据不存在", "action": "创建数据", "expected": "成功", "priority": "P0", "purpose": "验证唯一性约束"},
                {"name": "唯一性校验-重复创建", "precondition": "数据已存在", "action": "创建相同数据", "expected": "业务错误（已存在）", "priority": "P0", "purpose": "验证重复检测"},
            ])

        # 状态转换规则
        if "状态" in text or "status" in text.lower():
            scenarios.extend([
                {"name": "状态转换-合法转换", "precondition": "源状态合法", "action": "执行状态转换", "expected": "转换成功", "priority": "P0", "purpose": "验证合法状态流转"},
                {"name": "状态转换-非法转换", "precondition": "源状态不合法", "action": "执行状态转换", "expected": "业务错误", "priority": "P1", "purpose": "验证非法状态拦截"},
            ])

        # 权限规则
        if "权限" in text or "permission" in text.lower():
            scenarios.extend([
                {"name": "权限校验-有权限", "precondition": "已登录且有权限", "action": "访问接口", "expected": "成功", "priority": "P0", "purpose": "验证权限控制"},
                {"name": "权限校验-无权限", "precondition": "已登录但无权限", "action": "访问接口", "expected": "权限错误", "priority": "P0", "purpose": "验证权限拦截"},
                {"name": "权限校验-未登录", "precondition": "未登录", "action": "访问接口", "expected": "认证错误", "priority": "P0", "purpose": "验证认证控制"},
            ])

        # 默认场景
        if not scenarios:
            scenarios.extend([
                {"name": "正常业务流程", "precondition": "数据准备完成", "action": "执行业务操作", "expected": "业务成功", "priority": "P0", "purpose": "验证核心功能"},
                {"name": "业务规则违反", "precondition": "不满足业务条件", "action": "执行业务操作", "expected": "业务错误", "priority": "P1", "purpose": "验证规则校验"},
            ])

        lines.append("| 测试场景 | 前置条件 | 操作步骤 | 预期结果 | 优先级 | 测试目的 |")
        lines.append("|----------|----------|----------|----------|--------|----------|")

        for scenario in scenarios:
            lines.append(f"| {scenario['name']} | {scenario['precondition']} | {scenario['action']} | {scenario['expected']} | {scenario['priority']} | {scenario['purpose']} |")

        lines.append("")

    def _analyze_response(self, lines: List[str], operation: Dict[str, Any]):
        """分析响应验证"""
        lines.append("#### 响应验证测试点分析")
        lines.append("")

        # 成功响应
        lines.append("**成功响应（2xx）验证**：")
        lines.append("")
        lines.append("| 验证项 | 验证内容 | 优先级 | 验证方法 |")
        lines.append("|--------|----------|--------|----------|")
        lines.append("| 响应结构 | 包含code, message, data字段 | P0 | 检查JSON结构 |")
        lines.append("| 状态码 | 与业务结果匹配（200/201） | P0 | 检查HTTP状态码 |")
        lines.append("| 响应时间 | 符合性能要求 | P1 | 记录响应时间 |")
        lines.append("| 数据完整性 | 返回完整业务数据 | P0 | 检查data字段 |")
        lines.append("| 字段类型 | 每个字段匹配规格 | P1 | 验证字段类型 |")
        lines.append("")

        # 错误响应
        lines.append("**错误响应（4xx/5xx）验证**：")
        lines.append("")
        lines.append("| 错误场景 | 状态码 | 响应体验证 | 优先级 |")
        lines.append("|----------|--------|------------|--------|")
        lines.append("| 参数缺失 | 400 | code=400, message包含'必填' | P0 |")
        lines.append("| 参数格式错误 | 400 | code=400, message包含'格式' | P0 |")
        lines.append("| 参数类型错误 | 400 | code=400, message包含'类型' | P0 |")
        lines.append("| 业务规则违反 | 409 | code=409, message包含'已存在' | P0 |")
        lines.append("| 未认证 | 401 | code=401, message包含'认证' | P0 |")
        lines.append("| 无权限 | 403 | code=403, message包含'权限' | P0 |")
        lines.append("| 资源不存在 | 404 | code=404, message包含'不存在' | P0 |")
        lines.append("| 服务器异常 | 500 | code=500, message不包含敏感信息 | P0 |")
        lines.append("")

    def _analyze_security(self, lines: List[str]):
        """分析安全测试"""
        lines.append("#### 安全测试点分析")
        lines.append("")

        # 认证安全
        lines.append("**认证安全**：")
        lines.append("")
        lines.append("| 测试场景 | 测试操作 | 预期结果 | 风险等级 | 测试目的 |")
        lines.append("|----------|----------|----------|----------|----------|")
        lines.append("| 未认证访问 | 不携带Token调用接口 | 返回401 Unauthorized | 🔴 高 | 验证认证拦截 |")
        lines.append("| Token过期 | 使用过期Token | 返回401, message提示Token过期 | 🔴 高 | 验证Token过期处理 |")
        lines.append("| Token篡改 | 修改Token签名 | 返回401, message提示Token无效 | 🔴 高 | 验证Token完整性 |")
        lines.append("| Token刷新 | 使用RefreshToken获取新Token | 返回新Token, 旧Token失效 | 🟡 中 | 验证Token刷新机制 |")
        lines.append("")

        # 授权安全
        lines.append("**授权安全**：")
        lines.append("")
        lines.append("| 测试场景 | 测试操作 | 预期结果 | 风险等级 | 测试目的 |")
        lines.append("|----------|----------|----------|----------|----------|")
        lines.append("| 越权访问 | 用户A访问用户B的数据 | 返回403 Forbidden | 🔴 高 | 验证水平越权防护 |")
        lines.append("| 垂直越权 | 普通用户访问管理员接口 | 返回403 Forbidden | 🔴 高 | 验证垂直越权防护 |")
        lines.append("| 权限变更 | 权限变更后访问接口 | 按新权限控制 | 🟡 中 | 验证权限变更生效 |")
        lines.append("")

        # 数据安全
        lines.append("**数据安全**：")
        lines.append("")
        lines.append("| 测试场景 | 测试操作 | 预期结果 | 风险等级 | 测试目的 |")
        lines.append("|----------|----------|----------|----------|----------|")
        lines.append("| SQL注入 | 输入SQL特殊字符 | 返回400, 不被注入 | 🔴 高 | 验证SQL注入防护 |")
        lines.append("| XSS攻击 | 输入<script>标签 | 返回400, 内容被转义 | 🔴 高 | 验证XSS防护 |")
        lines.append("| 敏感数据泄露 | 检查响应字段 | 密码、密钥不返回 | 🔴 高 | 验证数据脱敏 |")
        lines.append("| 日志脱敏 | 检查日志文件 | 敏感信息被脱敏 | 🟡 中 | 验证日志安全 |")
        lines.append("")

    def _analyze_performance(self, lines: List[str]):
        """分析性能测试"""
        lines.append("#### 性能测试点分析")
        lines.append("")

        lines.append("**响应时间要求**：")
        lines.append("")
        lines.append("- **P0优先级接口**：< 200ms (95分位)")
        lines.append("- **P1优先级接口**：< 500ms (95分位)")
        lines.append("- **P2优先级接口**：< 1000ms (95分位)")
        lines.append("- **P3优先级接口**：< 2000ms (95分位)")
        lines.append("")

        lines.append("**压力测试场景**：")
        lines.append("")
        lines.append("| 场景 | 并发数 | 持续时间 | 预期结果 | 关注点 |")
        lines.append("|------|--------|----------|----------|--------|")
        lines.append("| 基准测试 | 1 | 10分钟 | 响应稳定 | 基准响应时间 |")
        lines.append("| 负载测试 | 10 | 30分钟 | 成功率>99.9% | 系统负载 |")
        lines.append("| 压力测试 | 50 | 15分钟 | 成功率>99% | 系统瓶颈 |")
        lines.append("| 峰值测试 | 100 | 5分钟 | 不崩溃 | 最大承载能力 |")
        lines.append("")


def main():
    """主函数"""
    parser = argparse.ArgumentParser(description='API测试分析文档生成器')
    parser.add_argument('--input', '-i', required=True, help='输入文件（OpenAPI/Swagger/简化定义）')
    parser.add_argument('--output', '-o', help='输出Markdown文件（默认：stdout）')
    parser.add_argument('--format', '-f', choices=['openapi', 'simple'], default='openapi',
                        help='输入格式（默认：openapi）')
    parser.add_argument('--config', '-c', help='配置文件路径')
    parser.add_argument('--api-name', '-n', help='API名称')

    args = parser.parse_args()

    try:
        analyzer = APITestAnalyzer(args.config)

        if Path(args.input).exists():
            with open(args.input, 'r', encoding='utf-8') as f:
                input_content = f.read()
        else:
            input_content = args.input

        if args.format == 'openapi':
            analysis = analyzer.analyze_from_openapi(input_content, args.api_name)
        else:
            analysis = analyzer.analyze_from_simple(input_content)

        if args.output:
            Path(args.output).parent.mkdir(parents=True, exist_ok=True)
            with open(args.output, 'w', encoding='utf-8') as f:
                f.write(analysis)
            logger.info(f"测试分析文档已保存到: {args.output}")
        else:
            print(analysis)

    except Exception as e:
        logger.error(f"生成失败: {e}", exc_info=True)
        sys.exit(1)


if __name__ == "__main__":
    main()


path: scripts/utils.py
content: #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
工具函数模块
提供参数解析、测试数据生成、验证等辅助功能
"""

import re
import random
import string
from typing import Dict, List, Any, Optional, Union
from datetime import datetime, timedelta
import uuid


def generate_test_value(param_type: str, constraint: Optional[Dict[str, Any]] = None) -> Any:
    """
    根据参数类型和约束生成测试值

    Args:
        param_type: 参数类型 (string, integer, number, boolean, array, object)
        constraint: 约束条件

    Returns:
        测试值
    """
    constraint = constraint or {}

    if param_type == "string":
        return generate_string_value(constraint)
    elif param_type == "integer":
        return generate_integer_value(constraint)
    elif param_type == "number":
        return generate_number_value(constraint)
    elif param_type == "boolean":
        return generate_boolean_value(constraint)
    elif param_type == "array":
        return generate_array_value(constraint)
    elif param_type == "object":
        return generate_object_value(constraint)
    else:
        return "test_value"


def generate_string_value(constraint: Dict[str, Any]) -> str:
    """
    生成字符串测试值

    Args:
        constraint: 约束条件

    Returns:
        字符串测试值
    """
    min_length = constraint.get("minLength", 1)
    max_length = constraint.get("maxLength", 20)
    pattern = constraint.get("pattern")
    enum_values = constraint.get("enum", [])
    format_type = constraint.get("format")

    # 如果有枚举值，返回第一个
    if enum_values:
        return enum_values[0]

    # 根据format生成特定格式
    if format_type == "email":
        return "[REDACTED_SECRET]"
    elif format_type == "phone":
        return "13800138000"
    elif format_type == "date":
        return datetime.now().strftime("%Y-%m-%d")
    elif format_type == "date-time":
        return datetime.now().isoformat()
    elif format_type == "uuid":
        return str(uuid.uuid4())
    elif format_type == "uri":
        return "https://example.com"

    # 根据pattern生成
    if pattern:
        return generate_value_by_pattern(pattern, min_length, max_length)

    # 根据长度生成
    length = min_length if min_length > 0 else min(max_length, 10)
    return "a" * length


def generate_integer_value(constraint: Dict[str, Any]) -> int:
    """
    生成整数测试值

    Args:
        constraint: 约束条件

    Returns:
        整数测试值
    """
    minimum = constraint.get("minimum", 0)
    maximum = constraint.get("maximum", 100)
    enum_values = constraint.get("enum", [])

    if enum_values:
        return enum_values[0]

    # 返回范围内的值
    return (minimum + maximum) // 2


def generate_number_value(constraint: Dict[str, Any]) -> float:
    """
    生成数字测试值

    Args:
        constraint: 约束条件

    Returns:
        数字测试值
    """
    minimum = constraint.get("minimum", 0.0)
    maximum = constraint.get("maximum", 100.0)

    return round((minimum + maximum) / 2, 2)


def generate_boolean_value(constraint: Dict[str, Any]) -> bool:
    """
    生成布尔测试值

    Args:
        constraint: 约束条件

    Returns:
        布尔测试值
    """
    return True


def generate_array_value(constraint: Dict[str, Any]) -> List[Any]:
    """
    生成数组测试值

    Args:
        constraint: 约束条件

    Returns:
        数组测试值
    """
    min_items = constraint.get("minItems", 0)
    max_items = constraint.get("maxItems", 10)
    item_type = constraint.get("items", {}).get("type", "string")

    item_count = min_items if min_items > 0 else min(max_items, 3)

    return [generate_test_value(item_type) for _ in range(item_count)]


def generate_object_value(constraint: Dict[str, Any]) -> Dict[str, Any]:
    """
    生成对象测试值

    Args:
        constraint: 约束条件

    Returns:
        对象测试值
    """
    properties = constraint.get("properties", {})
    result = {}

    for prop_name, prop_spec in properties.items():
        prop_type = prop_spec.get("type", "string")
        result[prop_name] = generate_test_value(prop_type, prop_spec)

    return result


def generate_value_by_pattern(pattern: str, min_length: int = 1, max_length: int = 20) -> str:
    """
    根据正则表达式生成测试值

    Args:
        pattern: 正则表达式
        min_length: 最小长度
        max_length: 最大长度

    Returns:
        符合模式的测试值
    """
    # 简单的正则到测试值映射
    pattern_map = {
        r"^[a-zA-Z0-9_]+$": "test_user_123",
        r"^[a-zA-Z]+$": "test",
        r"^[0-9]+$": "123456",
        r"^[a-zA-Z0-9]+$": "test123",
        r"^\\d{6}$": "123456",
        r"^\\d{11}$": "13800138000",
    }

    for regex, value in pattern_map.items():
        if re.match(regex, pattern):
            return value

    # 默认返回
    return "test_value"


def generate_invalid_value(param_type: str, constraint: Optional[Dict[str, Any]] = None) -> Any:
    """
    生成无效测试值（用于边界和异常测试）

    Args:
        param_type: 参数类型
        constraint: 约束条件

    Returns:
        无效测试值
    """
    constraint = constraint or {}

    if param_type == "string":
        return generate_invalid_string(constraint)
    elif param_type == "integer":
        return generate_invalid_integer(constraint)
    elif param_type == "number":
        return generate_invalid_number(constraint)
    elif param_type == "boolean":
        return "invalid_boolean"
    elif param_type == "array":
        return "invalid_array"
    else:
        return "invalid_value"


def generate_invalid_string(constraint: Dict[str, Any]) -> str:
    """
    生成无效字符串

    Args:
        constraint: 约束条件

    Returns:
        无效字符串
    """
    min_length = constraint.get("minLength", 0)
    max_length = constraint.get("maxLength", 20)
    enum_values = constraint.get("enum", [])
    format_type = constraint.get("format")

    # 如果是最小长度>0，返回空字符串
    if min_length > 0:
        return ""

    # 如果是枚举，返回不在枚举中的值
    if enum_values:
        return "invalid_enum_value"

    # 根据format返回无效值
    if format_type == "email":
        return "invalid-email"
    elif format_type == "phone":
        return "13800"  # 太短

    # 超长字符串
    return "a" * (max_length + 1)


def generate_invalid_integer(constraint: Dict[str, Any]) -> Union[int, str]:
    """
    生成无效整数

    Args:
        constraint: 约束条件

    Returns:
        无效整数值
    """
    minimum = constraint.get("minimum")
    maximum = constraint.get("maximum")
    enum_values = constraint.get("enum", [])

    # 返回小于最小值的数
    if minimum is not None:
        return minimum - 1

    # 返回大于最大值的数
    if maximum is not None:
        return maximum + 1

    # 返回字符串
    return "invalid_integer"


def generate_invalid_number(constraint: Dict[str, Any]) -> Union[float, str]:
    """
    生成无效数字

    Args:
        constraint: 约束条件

    Returns:
        无效数字值
    """
    return generate_invalid_integer(constraint)


def is_sql_injection(value: str) -> bool:
    """
    检测是否为SQL注入攻击

    Args:
        value: 输入值

    Returns:
        是否为SQL注入
    """
    sql_patterns = [
        r".*'.*OR.*'.*=.*'.*",
        r".*;.*DROP\s+.*",
        r".*;.*DELETE\s+.*",
        r".*;.*UPDATE\s+.*",
        r".*UNION\s+SELECT.*",
        r"'.*--.*",
        r"'.*/\*.*\*/.*",
    ]

    for pattern in sql_patterns:
        if re.match(pattern, value, re.IGNORECASE):
            return True

    return False


def is_xss(value: str) -> bool:
    """
    检测是否为XSS攻击

    Args:
        value: 输入值

    Returns:
        是否为XSS
    """
    xss_patterns = [
        r"<script[^>]*>.*</script>",
        r"<[^>]+on\w+\s*=.*>",
        r"javascript:",
        r"vbscript:",
        r"onerror\s*=",
        r"onload\s*=",
        r"onclick\s*=",
        r"<iframe[^>]*>",
        r"<object[^>]*>",
        r"<embed[^>]*>",
    ]

    for pattern in xss_patterns:
        if re.search(pattern, value, re.IGNORECASE):
            return True

    return False


def validate_email(email: str) -> bool:
    """
    验证邮箱格式

    Args:
        email: 邮箱地址

    Returns:
        是否有效
    """
    pattern = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
    return re.match(pattern, email) is not None


def validate_phone(phone: str) -> bool:
    """
    验证手机号格式

    Args:
        phone: 手机号

    Returns:
        是否有效
    """
    pattern = r"^1[3-9]\d{9}$"
    return re.match(pattern, phone) is not None


def validate_url(url: str) -> bool:
    """
    验证URL格式

    Args:
        url: URL地址

    Returns:
        是否有效
    """
    pattern = r"^https?://[a-zA-Z0-9.-]+(:\d+)?(/.*)?$"
    return re.match(pattern, url) is not None


def validate_uuid(uuid_str: str) -> bool:
    """
    验证UUID格式

    Args:
        uuid_str: UUID字符串

    Returns:
        是否有效
    """
    try:
        uuid.UUID(uuid_str)
        return True
    except ValueError:
        return False


def calculate_boundary_values(min_value: Optional[Union[int, float]] = None,
                              max_value: Optional[Union[int, float]] = None) -> Dict[str, Any]:
    """
    计算边界值

    Args:
        min_value: 最小值
        max_value: 最大值

    Returns:
        边界值字典
    """
    result = {}

    if min_value is not None:
        result["minimum"] = min_value
        result["just_above_minimum"] = min_value + 1 if isinstance(min_value, int) else min_value + 0.1
        result["just_below_minimum"] = min_value - 1 if isinstance(min_value, int) else min_value - 0.1

    if max_value is not None:
        result["maximum"] = max_value
        result["just_below_maximum"] = max_value - 1 if isinstance(max_value, int) else max_value - 0.1
        result["just_above_maximum"] = max_value + 1 if isinstance(max_value, int) else max_value + 0.1

    return result


def format_test_value(value: Any) -> str:
    """
    格式化测试值为可读字符串

    Args:
        value: 测试值

    Returns:
        格式化后的字符串
    """
    if value is None:
        return "null"
    elif isinstance(value, str):
        # 处理特殊字符
        if "<" in value or ">" in value:
            return f'"{value}"'
        elif "'" in value:
            return f'"{value}"'
        else:
            return f'"{value}"'
    elif isinstance(value, (int, float)):
        return str(value)
    elif isinstance(value, list):
        return str(value)
    elif isinstance(value, dict):
        return str(value)
    else:
        return repr(value)


def get_priority(rule_type: str, config: Optional[Dict[str, Any]] = None) -> str:
    """
    获取测试优先级

    Args:
        rule_type: 规则类型
        config: 配置

    Returns:
        优先级（P0/P1/P2）
    """
    config = config or {}
    priority_rules = config.get("priority_rules", {})

    return priority_rules.get(rule_type, "P1")


def count_test_points(test_points: Dict[str, List[Dict[str, Any]]]) -> Dict[str, int]:
    """
    统计测试点数量

    Args:
        test_points: 测试点字典

    Returns:
        统计结果
    """
    stats = {}
    total = 0

    for category, points in test_points.items():
        count = len(points)
        stats[category] = count
        total += count

    stats["total"] = total
    return stats


def generate_summary(stats: Dict[str, int]) -> str:
    """
    生成统计摘要

    Args:
        stats: 统计数据

    Returns:
        摘要字符串
    """
    lines = []

    category_names = {
        "parameter_tests": "参数校验",
        "business_logic_tests": "业务逻辑",
        "response_tests": "响应验证",
        "security_tests": "安全测试",
        "performance_tests": "性能测试"
    }

    for category, count in stats.items():
        if category == "total":
            continue
        name = category_names.get(category, category)
        lines.append(f"- {name}：{count}个测试点")

    lines.append(f"- **总计：{stats.get('total', 0)}个测试点**")

    return "\n".join(lines)


if __name__ == "__main__":
    # 测试工具函数
    print("=== 测试值生成示例 ===")

    print("字符串:", generate_test_value("string", {"minLength": 3, "maxLength": 20}))
    print("整数:", generate_test_value("integer", {"minimum": 0, "maximum": 100}))
    print("数字:", generate_test_value("number", {"minimum": 0.0, "maximum": 100.0}))
    print("布尔:", generate_test_value("boolean"))
    print("数组:", generate_test_value("array", {"minItems": 1, "maxItems": 5}))

    print("\n=== 无效值生成示例 ===")
    print("无效字符串:", generate_invalid_value("string", {"minLength": 3}))
    print("无效整数:", generate_invalid_value("integer", {"minimum": 0}))

    print("\n=== 安全检测示例 ===")
    print("SQL注入检测:", is_sql_injection("' OR '1'='1"))
    print("XSS检测:", is_xss("<script>alert(1)</script>"))

    print("\n=== 格式验证示例 ===")
    print("邮箱验证:", validate_email("[REDACTED_SECRET]"))
    print("手机号验证:", validate_phone("13800138000"))
    print("UUID验证:", validate_uuid(str(uuid.uuid4())))

    print("\n=== 边界值计算示例 ===")
    boundaries = calculate_boundary_values(0, 100)
    print("边界值:", boundaries)


path: references/common-pitfalls.md
content: # 接口测试100个高频易错点清单

> 涵盖请求规范、参数处理、数据校验、业务逻辑、性能安全、兼容适配六大核心维度

---

## 一、请求层基础规范（1-15）

| 序号 | 易错点 | 测试方法 | 预期结果 |
|------|--------|----------|----------|
| 1 | 请求方法错误（GET用成POST、DELETE用成PUT，或非幂等接口用GET） | 使用错误的HTTP方法调用接口 | 返回405 Method Not Allowed或明确错误提示 |
| 2 | 请求头缺失必选字段（如Token、Content-Type、Accept） | 删除必选请求头后调用 | 返回401或明确提示缺少必选头 |
| 3 | Content-Type与实际传参格式不匹配 | json传参却设为form-data | 返回400参数格式错误 |
| 4 | 请求头字段值格式错误 | Token拼接多余空格、时间戳单位不统一 | 返回401或格式错误提示 |
| 5 | 接口地址拼写错误 | 修改URL路径字符 | 返回404 Not Found |
| 6 | 跨域请求未携带CORS相关头 | 跨域调用不传Origin头 | 返回CORS错误或正确处理跨域 |
| 7 | 请求协议错误 | 生产环境用HTTP调用HTTPS接口 | 返回协议错误或自动重定向 |
| 8 | 请求超时时间未设置/设置不当 | 设置极短超时（如1ms） | 返回超时错误，不无限等待 |
| 9 | 批量请求未做连接复用 | 高频调用观察TCP连接数 | 应复用连接，无频繁创建 |
| 10 | 请求体编码格式错误 | 中文用非UTF-8编码 | 正确处理或返回编码错误 |
| 11 | GET请求传参过长 | URL超过2048字符 | 返回414 URI Too Long |
| 12 | POST请求体为空但要求必传 | 发送空请求体 | 返回参数缺失错误 |
| 13 | 请求重定向未处理 | 接口返回301/302 | 正确跟随重定向或返回提示 |
| 14 | 多环境地址混淆 | 测试环境用生产地址 | 环境隔离，返回错误或提示 |
| 15 | 接口版本号未传/传错 | 传错误的version参数 | 返回版本错误或调用正确版本 |

---

## 二、参数处理与校验（16-45）

### （一）必选/可选参数（16-25）

| 序号 | 易错点 | 测试方法 | 预期结果 |
|------|--------|----------|----------|
| 16 | 必选参数完全缺失，接口未返回明确错误提示 | 删除必选参数 | 返回明确的参数缺失提示 |
| 17 | 必选参数传空值（""、null、undefined） | 传空字符串/null | 返回参数无效错误 |
| 18 | 可选参数传非法值时，接口未做默认值兜底 | 可选参数传非法值 | 使用默认值或忽略 |
| 19 | 多参数组合时，部分必选参数缺失 | 传部分必选参数 | 返回缺失参数提示 |
| 20 | 参数名大小写错误 | userID写成userid | 返回参数错误或兼容处理 |
| 21 | 参数名拼写错误 | mobile写成moblie | 返回参数错误 |
| 22 | 重复传参 | 同一参数在URL和Body中同时传 | 明确取值规则，无歧义 |
| 23 | 多余参数传参 | 传未定义的参数 | 忽略或返回警告 |
| 24 | 动态参数传固定值 | /api/{id}传非占位符值 | 正确解析或返回错误 |
| 25 | 批量参数中部分必选参数缺失 | 批量请求中某条缺失必选项 | 返回具体哪条缺失 |

### （二）参数格式与类型（26-35）

| 序号 | 易错点 | 测试方法 | 预期结果 |
|------|--------|----------|----------|
| 26 | 字符串参数传数值类型 | name传123 | 类型转换或返回类型错误 |
| 27 | 数值参数传字符串/特殊字符 | age传"二十"、"12a" | 返回类型格式错误 |
| 28 | 数值参数超出取值范围 | 年龄传-1、200，金额传负数 | 返回范围错误 |
| 29 | 浮点型参数精度丢失 | 金额传0.019999 | 存储和返回精度正确 |
| 30 | 布尔参数传非true/false值 | 传1/0、"true"/"false" | 类型转换或返回错误 |
| 31 | 日期参数格式错误 | yyyy-mm-dd写成yyyy/mm/dd | 返回日期格式错误 |
| 32 | 数组参数传非数组格式 | 传"1,2,3"而非[1,2,3] | 返回格式错误 |
| 33 | 数组参数为空数组（[]） | 传空数组[] | 正确处理，不报错 |
| 34 | 对象参数传非对象格式 | 传字符串而非{} | 返回格式错误 |
| 35 | 枚举参数传非枚举值 | 性别传3，枚举仅0/1 | 返回枚举值错误 |

### （三）参数长度与边界（36-45）

| 序号 | 易错点 | 测试方法 | 预期结果 |
|------|--------|----------|----------|
| 36 | 字符串参数长度为0 | 传空字符串"" | 返回最小长度错误 |
| 37 | 字符串参数超过最大长度限制 | 用户名限20字符，传21字符 | 返回超长错误 |
| 38 | 数组参数元素数量超限 | 批量操作限50条，传51条 | 返回数量超限错误 |
| 39 | 数值参数为0，接口未做零值校验 | 分页size传0 | 返回参数错误或使用默认值 |
| 40 | 数值参数为最大/最小临界值 | int型传2147483647 | 正确处理，不溢出 |
| 41 | 固定长度参数长度不符 | 手机号传10位/12位 | 返回长度错误 |
| 42 | 密码未满足复杂度 | 纯数字密码 | 返回复杂度不足错误 |
| 43 | 文本参数包含特殊字符 | 传<、>、&、'、" | 正确转义处理 |
| 44 | 分页参数传负数 | pageNum=-1 | 返回参数错误 |
| 45 | 多条件查询参数边界组合 | 极端参数组合 | 结果正确或友好提示 |

---

## 三、响应结果校验（46-65）

### （一）响应基础信息（46-55）

| 序号 | 易错点 | 测试方法 | 预期结果 |
|------|--------|----------|----------|
| 46 | 状态码返回错误 | 成功操作返回500 | 状态码正确反映结果 |
| 47 | 状态码与业务码不匹配 | 200状态码+失败业务码 | 状态码与业务码一致 |
| 48 | 响应头缺失必选字段 | 检查Set-Cookie等 | 必选响应头存在 |
| 49 | 响应体编码格式错误 | 检查响应编码 | UTF-8编码，无乱码 |
| 50 | 响应超时 | 长时间操作 | 在约定时间返回或超时提示 |
| 51 | 响应体为空但要求返回数据 | 查询操作 | 返回空数组而非空响应体 |
| 52 | 响应体多余字段 | 对比接口文档 | 仅返回文档定义字段 |
| 53 | 响应体缺失必选字段 | 检查必返字段 | 所有必返字段存在 |
| 54 | 响应字段名与文档不一致 | 对比字段名 | 字段名与文档一致 |
| 55 | 响应字段值类型与文档不符 | 检查字段类型 | 类型与文档定义一致 |

### （二）业务数据与逻辑（56-65）

| 序号 | 易错点 | 测试方法 | 预期结果 |
|------|--------|----------|----------|
| 56 | 业务码返回错误 | 成功操作检查code | 业务码正确 |
| 57 | 错误提示信息不明确 | 触发错误场景 | 返回具体错误原因 |
| 58 | 相同请求多次返回结果不一致 | 相同参数调用多次 | 静态数据结果一致 |
| 59 | 动态数据返回不实时 | 新增后立即查询 | 返回最新数据 |
| 60 | 分页总条数计算错误 | 验证total字段 | 总条数计算正确 |
| 61 | 排序结果未按指定字段排序 | 传排序参数 | 结果按指定字段排序 |
| 62 | 过滤结果包含不符合条件数据 | 传过滤条件 | 结果全部符合条件 |
| 63 | 批量操作结果与实际不符 | 批量操作5条 | 返回结果与实际一致 |
| 64 | 空结果集返回格式错误 | 查询无结果 | 返回[]而非null |
| 65 | 响应数据精度丢失 | 查询金额0.01 | 返回精确值 |

---

## 四、业务逻辑与流程（66-80）

| 序号 | 易错点 | 测试方法 | 预期结果 |
|------|--------|----------|----------|
| 66 | 接口未做幂等性处理 | 重复提交订单 | 仅创建一条订单 |
| 67 | 幂等性标识校验失效 | 相同requestId重复请求 | 拒绝重复请求 |
| 68 | 接口权限校验缺失 | 无Token访问 | 返回401 Unauthorized |
| 69 | 越权访问 | A用户访问B用户数据 | 返回403 Forbidden |
| 70 | 数据关联逻辑错误 | 创建订单不传用户ID | 返回参数错误 |
| 71 | 状态流转错误 | 未付款订单直接发货 | 返回状态错误 |
| 72 | 关联表未同步更新 | 删除用户后查订单 | 订单已标记作废 |
| 73 | 条件分支逻辑遗漏 | 传未处理的参数组合 | 有明确处理或错误提示 |
| 74 | 异常场景未做兜底 | 查询不存在的ID | 返回友好提示，不抛异常 |
| 75 | 批量操作全成功/全失败 | 批量操作中部分失败 | 返回部分成功详情 |
| 76 | 前置条件未满足仍执行 | 未登录提交订单 | 返回未登录错误 |
| 77 | 前置接口失败后续仍调用 | 流程中断 | 后续接口不执行 |
| 78 | 数据唯一性校验失效 | 重复注册手机号 | 返回已注册错误 |
| 79 | 数据有效期校验失效 | 使用过期验证码 | 返回验证码过期 |
| 80 | 业务规则冲突 | 优惠券叠加超限 | 返回超限错误 |

---

## 五、性能与并发（81-90）

| 序号 | 易错点 | 测试方法 | 预期结果 |
|------|--------|----------|----------|
| 81 | 高并发请求服务器崩溃 | 1000 QPS压测 | 服务稳定，无大量5xx |
| 82 | 并发导致数据脏读/脏写 | 多用户同时修改同一数据 | 数据一致性正确 |
| 83 | 接口响应时间过长 | 单接口性能测试 | P99 < 约定阈值 |
| 84 | 服务器资源耗尽 | 高负载测试 | 资源占用合理 |
| 85 | 接口未做限流处理 | 突发大流量 | 触发限流，服务稳定 |
| 86 | 大页码查询响应慢 | pageNum=10000 | 响应时间合理 |
| 87 | 批量操作未分批处理 | 传10000条数据 | 返回数量限制错误 |
| 88 | 第三方服务无超时控制 | 模拟第三方超时 | 本接口有超时兜底 |
| 89 | 高频查询未做缓存 | 重复查询相同数据 | 命中缓存，响应快 |
| 90 | 缓存与数据库不一致 | 修改数据后查询 | 返回最新数据 |

---

## 六、安全与兼容（91-100）

### （一）安全漏洞（91-95）

| 序号 | 易错点 | 测试方法 | 预期结果 |
|------|--------|----------|----------|
| 91 | SQL注入漏洞 | id=1 or 1=1 | 返回参数错误，不返回全量数据 |
| 92 | XSS漏洞 | name=<script>alert(1)</script> | 转义处理，不执行脚本 |
| 93 | CSRF漏洞 | 跨站不带Token请求 | 拒绝请求 |
| 94 | 敏感数据明文传输 | 查看密码/身份证字段 | 数据已脱敏或加密 |
| 95 | 接口未做频率限制 | 暴力调用验证码接口 | 触发频率限制 |

### （二）兼容与异常（96-100）

| 序号 | 易错点 | 测试方法 | 预期结果 |
|------|--------|----------|----------|
| 96 | 不同客户端结果不一致 | Chrome/IE/移动端分别调用 | 结果一致 |
| 97 | 不同环境行为不一致 | 测试/生产环境对比 | 行为一致 |
| 98 | 超大请求体导致崩溃 | 传100MB请求体 | 返回大小限制错误 |
| 99 | 网络中断未处理 | 模拟网络中断 | 有重试/降级机制 |
| 100 | 第三方服务挂掉未熔断 | 模拟第三方不可用 | 触发熔断，本服务可用 |

---

## 七、补充测试项（用户补充）

### （一）通用信息校验

| 序号 | 测试项 | 测试方法 | 预期结果 |
|------|--------|----------|----------|
| 101 | URL正确性 | 填写正确的URL | 正确访问接口 |
| 102 | URL错误 | 填写错误的URL | 访问不到，返回404 Not Found |
| 103 | 请求方法正确 | 使用正确的HTTP方法 | 请求成功 |
| 104 | 请求方法错误 | 使用错误的HTTP方法（如GET代替POST） | 返回405 Method Not Allowed |
| 105 | 请求头正确 | 正确传递Content-Type: application/json | 请求成功处理 |
| 106 | 请求头错误 | Content-Type与实际格式不匹配 | 返回400参数格式错误 |
| 107 | 接口鉴权正确 | 传递正确的token/session | 请求成功 |
| 108 | 接口鉴权缺失 | 不传认证信息 | 返回401 Unauthorized |
| 109 | 接口鉴权错误 | 传递错误的token/session | 返回401认证失败 |
| 110 | 认证信息失效 | 使用过期或失效的认证信息 | 返回401或重新登录提示 |

### （二）接口参数详细校验

| 序号 | 测试项 | 测试方法 | 预期结果 |
|------|--------|----------|----------|
| 111 | 必填项完整 | 传递所有必填项，值合法 | 请求成功 |
| 112 | 必填项不传 | 删除某个必填参数 | 返回明确的参数缺失提示 |
| 113 | 必填项为空值 | 参数传None/null | 返回参数无效错误 |
| 114 | 必填项为空字符串 | 参数传"" | 返回参数不能为空错误 |
| 115 | 选填项都不填 | 所有选填项都不传 | 请求成功，使用默认值 |
| 116 | 选填项部分传递 | 只传递部分选填项 | 请求成功，未传的使用默认值 |
| 117 | 参数长度超上限 | 参数值超过maxLength | 返回参数长度超限错误 |
| 118 | 参数长度低于下限 | 参数值小于minLength | 返回参数长度不足错误 |
| 119 | 参数长度等于上限 | 参数值等于maxLength | 请求成功 |
| 120 | 参数类型正确 | 传递正确的数据类型 | 请求成功 |
| 121 | 参数类型错误 | 传递错误的数据类型（如字符串传整数） | 返回类型错误 |
| 122 | 参数有效性范围内 | 传递有效范围内的值 | 请求成功 |
| 123 | 参数有效性范围外 | 传递超出范围的值（如负数金额） | 返回参数无效错误 |
| 124 | 唯一字段数据唯一 | 唯一字段传不同值 | 请求成功 |
| 125 | 唯一字段数据重复 | 唯一字段传重复值 | 返回重复错误 |
| 126 | 非唯一字段可重复 | 非唯一字段传重复值 | 请求成功 |
| 127 | 参数关联校验 | 同时传互斥参数 | 返回参数关联错误提示 |
| 128 | 参数依赖校验 | 依赖参数缺失 | 返回依赖参数缺失错误 |

### （三）其他补充项

| 序号 | 测试项 | 测试方法 | 预期结果 |
|------|--------|----------|----------|
| 129 | 幂等性-重复提交 | 多次提交相同请求 | 效果与一次提交相同 |
| 130 | 幂等性-抽奖场景 | 多次提交抽奖请求 | 只能成功一次 |
| 131 | 幂等性-修改订单 | 多次提交修改请求 | 数据最终一致，无重复变更 |
| 132 | 弱网环境-网络中断 | 提交过程中网络中断 | 事务回滚，无脏数据 |
| 133 | 弱网环境-支付场景 | 支付过程网络中断 | 不扣款或自动退款 |
| 134 | 分布式-数据同步 | nginx配置模拟分布式 | 数据正确同步 |
| 135 | 分布式-一致性 | 多节点同时操作 | 数据一致性保证 |
| 136 | 接口风格-RESTful | 检查URL命名、HTTP方法使用 | 符合RESTful规范 |
| 137 | 接口风格-规范性 | 检查状态码使用、资源命名 | 符合规范 |
| 138 | 敏感信息-传输加密 | 抓包检查传输数据 | 敏感信息已加密 |
| 139 | 敏感信息-日志脱敏 | 检查日志输出 | 敏感信息已脱敏 |
| 140 | 敏感信息-存储加密 | 检查数据库存储 | 敏感信息已加密存储 |

---

## 快速自检清单

### 接口测试必检项（Top 20）

```
□ 1. 必选参数缺失校验
□ 2. 参数类型/格式校验
□ 3. 参数边界值校验（最小、最大、空值）
□ 4. 状态码与业务码一致性
□ 5. 响应字段完整性
□ 6. 权限校验（未登录、越权）
□ 7. 幂等性校验
□ 8. SQL注入测试
□ 9. XSS攻击测试
□ 10. 数据唯一性校验
□ 11. 状态流转校验
□ 12. 分页查询正确性
□ 13. 排序功能正确性
□ 14. 过滤条件正确性
□ 15. 并发数据一致性
□ 16. 响应时间在阈值内
□ 17. 错误提示明确
□ 18. 空结果返回空数组[]
□ 19. 敏感数据脱敏
□ 20. 第三方服务超时兜底
```

---

## 按测试阶段分类

### 功能测试阶段重点（1-80）

| 阶段 | 重点序号 |
|------|----------|
| 冒烟测试 | 1, 16, 26, 46, 56, 68 |
| 参数校验 | 16-45 |
| 业务逻辑 | 66-80 |
| 响应校验 | 46-65 |

### 非功能测试阶段重点（81-100）

| 阶段 | 重点序号 |
|------|----------|
| 性能测试 | 81-90 |
| 安全测试 | 91-95 |
| 兼容测试 | 96-100 |

---

## 自动化测试用例生成建议

根据高频易错点，优先自动生成以下类型测试用例：

| 优先级 | 测试类型 | 覆盖易错点 |
|--------|----------|------------|
| P0 | 必选参数校验 | 16-18, 36-37 |
| P0 | 权限校验 | 68-69 |
| P0 | 幂等性校验 | 66-67 |
| P0 | SQL/XSS注入 | 91-92 |
| P1 | 参数类型校验 | 26-35 |
| P1 | 边界值校验 | 36-45 |
| P1 | 状态码校验 | 46-47, 56 |
| P1 | 响应字段校验 | 51-55 |
| P2 | 性能边界 | 86-87 |
| P2 | 兼容性 | 96-97 |


path: references/test-case-design.md
content: # 接口测试用例设计详细指南

## 一、参数校验测试用例设计

### 1. 字符串参数测试矩阵

| 测试维度 | 测试值 | 说明 |
|----------|--------|------|
| 空值 | `""`, `null`, `"   "` | 空字符串、null、纯空格 |
| 长度边界 | `min-1`, `min`, `max`, `max+1` | 边界值测试 |
| 字符类型 | 纯字母、纯数字、纯中文、混合 | 字符组成测试 |
| 特殊字符 | `<script>`, `' OR '1'='1`, `&lt;` | XSS、SQL注入测试 |
| Unicode | emoji、生僻字、日文韩文 | 多语言支持 |
| 格式 | 邮箱、手机号、身份证、URL | 正则格式校验 |

### 2. 数字参数测试矩阵

| 测试维度 | 测试值 | 说明 |
|----------|--------|------|
| 零值 | `0`, `-0`, `0.0` | 零的各种表示 |
| 正数边界 | `min-1`, `min`, `max`, `max+1` | 取值范围边界 |
| 负数边界 | 如果允许负数 | 负数边界值 |
| 精度 | `1.23456789`, `1.1e10` | 小数精度、科学计数法 |
| 类型转换 | `"123"`, `"abc"`, `true` | 类型转换测试 |
| 溢出 | `MAX_INT+1`, `-MAX_INT-1` | 整数溢出 |

### 3. 枚举参数测试矩阵

```python
def test_enum_parameter(api_path, param_name, valid_values):
    """
    枚举参数测试用例生成器
    
    Args:
        api_path: 接口路径
        param_name: 参数名
        valid_values: 有效枚举值列表
    
    Returns:
        测试用例列表
    """
    test_cases = []
    
    # 测试每个有效枚举值
    for value in valid_values:
        test_cases.append({
            "name": f"有效枚举值-{value}",
            "param": {param_name: value},
            "expected": "success"
        })
    
    # 测试无效枚举值
    invalid_values = [
        "INVALID_ENUM",
        "",
        None,
        999,
        "valid_enum_lower_case",  # 大小写测试
    ]
    
    for value in invalid_values:
        test_cases.append({
            "name": f"无效枚举值-{value}",
            "param": {param_name: value},
            "expected": "error"
        })
    
    return test_cases
```

---

## 二、业务逻辑测试用例设计

### 1. 状态机测试

```
状态转换图示例：

[待支付] --支付成功--> [已支付] --发货--> [已发货] --签收--> [已完成]
    |                     |
    --取消--> [已取消]   --退款--> [已退款]
```

**状态转换测试用例：**

| 当前状态 | 操作 | 目标状态 | 是否合法 |
|----------|------|----------|----------|
| 待支付 | 支付 | 已支付 | ✓ |
| 待支付 | 取消 | 已取消 | ✓ |
| 已支付 | 发货 | 已发货 | ✓ |
| 已支付 | 取消 | 已取消 | ✗ |
| 已支付 | 退款 | 已退款 | ✓ |
| 已发货 | 签收 | 已完成 | ✓ |

### 2. 并发场景测试

```python
import threading
import time

class ConcurrencyTest:
    """并发测试工具类"""
    
    def __init__(self, api_client, num_threads=10):
        self.client = api_client
        self.num_threads = num_threads
        self.results = []
        self.lock = threading.Lock()
    
    def concurrent_request(self, func, *args):
        """并发执行请求"""
        def worker():
            try:
                result = func(*args)
                with self.lock:
                    self.results.append({"success": True, "data": result})
            except Exception as e:
                with self.lock:
                    self.results.append({"success": False, "error": str(e)})
        
        threads = [threading.Thread(target=worker) for _ in range(self.num_threads)]
        for t in threads:
            t.start()
        for t in threads:
            t.join()
        
        return self.results
    
    def test_concurrent_update(self, resource_id):
        """测试并发更新"""
        return self.concurrent_request(
            self.client.update_resource,
            resource_id,
            {"value": time.time()}
        )
```

### 3. 数据一致性测试

```python
def test_data_consistency_after_create(api_client, db_client):
    """创建后数据一致性测试"""
    
    # 1. 调用API创建数据
    create_data = {
        "name": "测试产品",
        "price": 99.99,
        "stock": 100
    }
    response = api_client.create_product(create_data)
    product_id = response["data"]["id"]
    
    # 2. 直接查询数据库验证
    db_record = db_client.query(
        "SELECT * FROM products WHERE id = ?", 
        (product_id,)
    )
    
    # 3. 比对API返回与数据库记录
    assert db_record["name"] == create_data["name"]
    assert float(db_record["price"]) == create_data["price"]
    assert db_record["stock"] == create_data["stock"]
    
    # 4. 通过API查询验证
    api_record = api_client.get_product(product_id)
    assert api_record["data"]["name"] == create_data["name"]
    assert api_record["data"]["price"] == create_data["price"]
    assert api_record["data"]["stock"] == create_data["stock"]
```

---

## 三、接口响应校验模板

### 1. 列表接口响应校验

```python
def validate_list_api_response(response, config):
    """
    列表接口响应校验器
    
    config = {
        "required_fields": ["id", "name", "status"],
        "field_types": {
            "id": int,
            "name": str,
            "status": int,
            "created_at": str
        },
        "pagination": True,
        "max_items": 100
    }
    """
    errors = []
    
    # 校验响应结构
    if "code" not in response:
        errors.append("缺少code字段")
    if "data" not in response:
        errors.append("缺少data字段")
        return errors
    
    data = response["data"]
    
    # 校验分页信息
    if config.get("pagination"):
        pagination_fields = ["total", "page", "page_size"]
        for field in pagination_fields:
            if field not in response:
                errors.append(f"缺少分页字段: {field}")
    
    # 校验列表项
    if not isinstance(data, list):
        errors.append("data字段应为数组")
        return errors
    
    if config.get("max_items") and len(data) > config["max_items"]:
        errors.append(f"返回数据超过最大限制: {len(data)} > {config['max_items']}")
    
    # 校验每条记录
    for i, item in enumerate(data):
        # 必填字段
        for field in config.get("required_fields", []):
            if field not in item:
                errors.append(f"第{i+1}条记录缺少字段: {field}")
        
        # 字段类型
        for field, expected_type in config.get("field_types", {}).items():
            if field in item and item[field] is not None:
                if not isinstance(item[field], expected_type):
                    errors.append(
                        f"第{i+1}条记录字段{field}类型错误: "
                        f"期望{expected_type}, 实际{type(item[field])}"
                    )
    
    return errors
```

### 2. 错误响应校验

```python
def validate_error_response(response, expected_error):
    """
    错误响应校验
    
    expected_error = {
        "code": 10001,
        "message_contains": "参数",
        "http_status": 400
    }
    """
    errors = []
    
    # 校验HTTP状态码
    if response.status_code != expected_error.get("http_status", 400):
        errors.append(
            f"HTTP状态码错误: 期望{expected_error.get('http_status')}, "
            f"实际{response.status_code}"
        )
    
    data = response.json()
    
    # 校验错误码
    if "code" in expected_error:
        if data.get("code") != expected_error["code"]:
            errors.append(
                f"错误码错误: 期望{expected_error['code']}, "
                f"实际{data.get('code')}"
            )
    
    # 校验错误信息
    if "message_contains" in expected_error:
        if expected_error["message_contains"] not in data.get("message", ""):
            errors.append(
                f"错误信息不包含: {expected_error['message_contains']}, "
                f"实际{data.get('message')}"
            )
    
    return errors
```

---

## 四、性能测试场景

### 1. 响应时间基准

| 接口类型 | P50 | P95 | P99 | 最大值 |
|----------|-----|-----|-----|--------|
| 简单查询 | <50ms | <100ms | <200ms | <500ms |
| 复杂查询 | <200ms | <500ms | <1000ms | <2000ms |
| 写入操作 | <100ms | <300ms | <500ms | <1000ms |
| 批量操作 | <500ms | <2000ms | <5000ms | <10000ms |

### 2. 性能测试脚本

```python
import time
import statistics
from concurrent.futures import ThreadPoolExecutor

def performance_test(api_func, num_requests=100, concurrency=10):
    """
    性能测试工具
    
    Args:
        api_func: 要测试的API函数
        num_requests: 总请求数
        concurrency: 并发数
    """
    response_times = []
    errors = []
    
    def make_request():
        start = time.time()
        try:
            api_func()
            return time.time() - start, None
        except Exception as e:
            return time.time() - start, str(e)
    
    with ThreadPoolExecutor(max_workers=concurrency) as executor:
        results = list(executor.map(lambda _: make_request(), range(num_requests)))
    
    for elapsed, error in results:
        response_times.append(elapsed * 1000)  # 转换为毫秒
        if error:
            errors.append(error)
    
    response_times.sort()
    
    return {
        "total_requests": num_requests,
        "success_count": num_requests - len(errors),
        "error_count": len(errors),
        "error_rate": len(errors) / num_requests * 100,
        "avg_ms": statistics.mean(response_times),
        "min_ms": min(response_times),
        "max_ms": max(response_times),
        "p50_ms": response_times[int(num_requests * 0.5)],
        "p95_ms": response_times[int(num_requests * 0.95)],
        "p99_ms": response_times[int(num_requests * 0.99)],
    }
```

---

## 五、补充测试场景设计

### 1. 通用信息校验测试设计

```python
def test_url_validation(api_client):
    """URL校验测试"""
    # 正确的URL
    response = api_client.request("GET", "/api/users/123")
    assert response.status_code in [200, 404]  # 资源存在或不存在但URL正确
    
    # 错误的URL
    response = api_client.request("GET", "/api/invalid/url/path")
    assert response.status_code == 404

def test_http_method_validation(api_client):
    """请求方法校验测试"""
    # 正确的请求方法
    response = api_client.post("/api/users", {"name": "test"})
    assert response.status_code in [200, 201]
    
    # 错误的请求方法
    response = api_client.get("/api/users", {"name": "test"})  # POST接口用GET
    assert response.status_code == 405

def test_request_header_validation(api_client):
    """请求头校验测试"""
    # 正确的Content-Type
    headers = {"Content-Type": "application/json"}
    response = api_client.post("/api/users", {"name": "test"}, headers=headers)
    assert response.status_code in [200, 201]
    
    # 错误的Content-Type
    headers = {"Content-Type": "application/x-www-form-urlencoded"}
    response = api_client.post("/api/users", "name=test", headers=headers)
    assert response.status_code == 400

def test_authentication_validation(api_client):
    """接口鉴权校验测试"""
    # 正确的token
    headers = {"Authorization": "Bearer valid_token"}
    response = api_client.get("/api/profile", headers=headers)
    assert response.status_code == 200
    
    # 不传认证信息
    response = api_client.get("/api/profile")
    assert response.status_code == 401
    
    # 错误的认证信息
    headers = {"Authorization": "Bearer invalid_token"}
    response = api_client.get("/api/profile", headers=headers)
    assert response.status_code == 401
    
    # 失效的认证信息
    headers = {"Authorization": "Bearer expired_token"}
    response = api_client.get("/api/profile", headers=headers)
    assert response.status_code == 401
```

### 2. 参数详细校验测试设计

```python
def test_required_parameter_validation(api_client):
    """必填项校验测试"""
    # 所有必填项完整
    data = {
        "username": "testuser",
        "password": "test123456",
        "email": "[REDACTED_SECRET]"
    }
    response = api_client.post("/api/register", data)
    assert response.status_code == 201
    
    # 必填项不传
    data = {
        "username": "testuser",
        "password": "test123456"
        # email缺失
    }
    response = api_client.post("/api/register", data)
    assert response.status_code == 400
    assert "email" in response.json()["message"]
    
    # 必填项传空值
    data = {
        "username": "testuser",
        "password": "test123456",
        "email": None
    }
    response = api_client.post("/api/register", data)
    assert response.status_code == 400
    
    # 必填项传空字符串
    data = {
        "username": "testuser",
        "password": "test123456",
        "email": ""
    }
    response = api_client.post("/api/register", data)
    assert response.status_code == 400

def test_optional_parameter_validation(api_client):
    """选填项校验测试"""
    # 选填项都不填
    required_data = {
        "username": "testuser",
        "password": "test123456",
        "email": "[REDACTED_SECRET]"
    }
    response = api_client.post("/api/register", required_data)
    assert response.status_code == 201
    
    # 传递部分选填项
    data = {
        "username": "testuser",
        "password": "test123456",
        "email": "[REDACTED_SECRET]",
        "phone": "13800138000",  # 选填项
        "age": 25  # 选填项
    }
    response = api_client.post("/api/register", data)
    assert response.status_code == 201

def test_parameter_length_validation(api_client):
    """参数长度校验测试"""
    # 超过最大长度
    data = {"username": "a" * 21}  # maxLength=20
    response = api_client.post("/api/register", data)
    assert response.status_code == 400
    
    # 低于最小长度
    data = {"username": "ab"}  # minLength=3
    response = api_client.post("/api/register", data)
    assert response.status_code == 400
    
    # 等于最大长度
    data = {"username": "a" * 20}
    response = api_client.post("/api/register", data)
    assert response.status_code == 201

def test_parameter_type_validation(api_client):
    """参数类型校验测试"""
    # 正确的数据类型
    data = {"age": 25}  # integer
    response = api_client.post("/api/register", data)
    assert response.status_code == 201
    
    # 错误的数据类型
    data = {"age": "25"}  # string instead of integer
    response = api_client.post("/api/register", data)
    assert response.status_code == 400

def test_parameter_uniqueness_validation(api_client, db_client):
    """参数唯一性校验测试"""
    # 唯一字段传不同值
    data1 = {"username": "user1", "email": "[REDACTED_SECRET]"}
    response1 = api_client.post("/api/register", data1)
    assert response1.status_code == 201
    
    data2 = {"username": "user2", "email": "[REDACTED_SECRET]"}
    response2 = api_client.post("/api/register", data2)
    assert response2.status_code == 201
    
    # 唯一字段传重复值
    data3 = {"username": "user3", "email": "[REDACTED_SECRET]"}  # 重复的email
    response3 = api_client.post("/api/register", data3)
    assert response3.status_code == 409  # Conflict
    assert "email" in response3.json()["message"]
```

### 3. 补充项测试设计

```python
def test_idempotency(api_client):
    """幂等性测试"""
    # 准备数据
    data = {
        "order_id": "ORDER_123",
        "amount": 100.00,
        "product_id": "PROD_456"
    }
    
    # 第一次提交
    response1 = api_client.post("/api/payment", data)
    assert response1.status_code == 200
    result1 = response1.json()
    
    # 第二次提交（重复）
    response2 = api_client.post("/api/payment", data)
    assert response2.status_code == 200
    result2 = response2.json()
    
    # 结果应该相同（幂等）
    assert result1["data"]["transaction_id"] == result2["data"]["transaction_id"]
    
    # 抽奖场景（只能成功一次）
    lottery_data = {"user_id": "USER_789", "activity_id": "ACT_001"}
    response1 = api_client.post("/api/lottery/draw", lottery_data)
    assert response1.status_code == 200
    assert response1.json()["data"]["prize"] is not None
    
    response2 = api_client.post("/api/lottery/draw", lottery_data)
    assert response2.status_code == 400  # 已抽奖
    assert "already participated" in response2.json()["message"]

def test_weak_network_environment(api_client):
    """弱网环境测试"""
    # 使用网络代理工具模拟弱网（如Charles、Fiddler）
    # 设置网络延迟或丢包率
    
    # 支付场景网络中断
    # 在请求发送过程中中断网络
    try:
        response = api_client.post("/api/payment", {"order_id": "ORDER_123"}, timeout=0.1)
    except TimeoutError:
        # 查询支付状态
        status_response = api_client.get("/api/payment/ORDER_123/status")
        # 应该没有扣款或已自动退款
        assert status_response.json()["data"]["status"] in ["pending", "refunded"]

def test_distributed_system(api_client):
    """分布式系统测试"""
    # 使用nginx配置多个后端服务
    # 模拟负载均衡
    
    # 数据同步测试
    data = {"resource_id": "RES_001", "value": 100}
    
    # 在不同节点上操作
    for i in range(3):
        response = api_client.post("/api/resource/update", data)
        assert response.status_code == 200
    
    # 查询所有节点的数据
    responses = []
    for node in ["node1", "node2", "node3"]:
        response = api_client.get(f"/api/resource/RES_001?node={node}")
        responses.append(response.json()["data"]["value"])
    
    # 所有节点数据应该一致
    assert len(set(responses)) == 1

def test_restful_style(api_client):
    """RESTful接口风格测试"""
    # URL命名规范
    # 资源集合用复数
    response = api_client.get("/api/users")  # 正确
    assert response.status_code == 200
    
    # 避免动词
    response = api_client.get("/api/getUsers")  # 不推荐
    # 应该返回404或重定向
    
    # HTTP方法使用正确
    # GET - 查询
    response = api_client.get("/api/users/123")
    assert response.status_code == 200
    
    # POST - 创建
    response = api_client.post("/api/users", {"name": "test"})
    assert response.status_code == 201
    
    # PUT - 全量更新
    response = api_client.put("/api/users/123", {"name": "updated"})
    assert response.status_code == 200
    
    # PATCH - 部分更新
    response = api_client.patch("/api/users/123", {"name": "patched"})
    assert response.status_code == 200
    
    # DELETE - 删除
    response = api_client.delete("/api/users/123")
    assert response.status_code == 204
    
    # 状态码使用正确
    # 2xx - 成功
    # 4xx - 客户端错误
    # 5xx - 服务端错误

def test_sensitive_info_encryption(api_client):
    """敏感信息加密测试"""
    # 登录接口
    login_data = {
        "username": "testuser",
        "password": "test123456"
    }
    response = api_client.post("/api/login", login_data)
    assert response.status_code == 200
    
    # 抓包检查传输数据（需要网络抓包工具）
    # 密码应该加密传输
    
    # 检查日志输出
    # 日志中不应包含明文密码
    import logging
    log_records = []
    
    def log_handler(record):
        log_records.append(record.getMessage())
    
    logging.getLogger().addHandler(logging.Handler())
    
    # 模拟登录
    api_client.post("/api/login", login_data)
    
    # 检查日志
    for log in log_records:
        assert "test123456" not in log  # 密码不应出现在日志
        assert "testuser" not in log   # 用户名也可能需要脱敏
    
    # 检查数据库存储
    db_record = db_client.query("SELECT * FROM users WHERE username = %s", ("testuser",))
    assert db_record["password"] != "test123456"  # 密码应该加密存储
    assert db_record["password"].startswith("$2b$")  # bcrypt加密
```

---

## 六、测试数据管理


path: examples/openapi-example.yaml
content: openapi: 3.0.0
info:
  title: 用户管理API
  version: 1.0.0
  description: 用户注册、登录、信息管理的RESTful API
servers:
  - url: https://api.example.com/v1
    description: 生产环境
  - url: https://staging-api.example.com/v1
    description: 预发布环境

paths:
  /api/users/register:
    post:
      summary: 用户注册
      description: 新用户注册接口，需要验证用户名、邮箱、手机号的唯一性
      tags:
        - 用户管理
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - username
                - password
                - email
              properties:
                username:
                  type: string
                  minLength: 3
                  maxLength: 20
                  pattern: '^[a-zA-Z0-9_]+$'
                  description: 用户名，只能包含字母、数字和下划线
                password:
                  type: string
                  minLength: 6
                  maxLength: 20
                  description: 密码，6-20位
                email:
                  type: string
                  format: email
                  description: 邮箱地址
                phone:
                  type: string
                  pattern: '^1[3-9]\d{9}$'
                  description: 手机号（可选）
                invite_code:
                  type: string
                  minLength: 6
                  maxLength: 6
                  description: 邀请码（可选）
      responses:
        '200':
          description: 注册成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  code:
                    type: integer
                    example: 0
                  message:
                    type: string
                    example: "success"
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                        description: 用户ID
                      username:
                        type: string
                        description: 用户名
                      email:
                        type: string
                        description: 邮箱
                      token:
                        type: string
                        description: JWT令牌
                      created_at:
                        type: string
                        format: date-time
                        description: 创建时间
        '400':
          description: 参数错误
          content:
            application/json:
              schema:
                type: object
                properties:
                  code:
                    type: integer
                    example: 1001
                  message:
                    type: string
                    example: "参数验证失败"
        '409':
          description: 资源冲突（用户名、邮箱或手机号已存在）
          content:
            application/json:
              schema:
                type: object
                properties:
                  code:
                    type: integer
                    example: 2001
                  message:
                    type: string
                    example: "用户名已存在"

  /api/users/login:
    post:
      summary: 用户登录
      description: 用户登录接口，支持用户名/邮箱/手机号+密码登录
      tags:
        - 用户管理
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - account
                - password
              properties:
                account:
                  type: string
                  description: 用户名、邮箱或手机号
                password:
                  type: string
                  description: 密码
                remember_me:
                  type: boolean
                  default: false
                  description: 记住登录状态
      responses:
        '200':
          description: 登录成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  code:
                    type: integer
                    example: 0
                  message:
                    type: string
                    example: "登录成功"
                  data:
                    type: object
                    properties:
                      user:
                        type: object
                        properties:
                          id:
                            type: integer
                          username:
                            type: string
                          email:
                            type: string
                          phone:
                            type: string
                      token:
                        type: string
                        description: JWT令牌
                      expires_in:
                        type: integer
                        description: 过期时间（秒）
        '401':
          description: 认证失败
          content:
            application/json:
              schema:
                type: object
                properties:
                  code:
                    type: integer
                    example: 3001
                  message:
                    type: string
                    example: "用户名或密码错误"

  /api/users/{id}:
    get:
      summary: 获取用户信息
      description: 根据用户ID获取详细信息
      tags:
        - 用户管理
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
          description: 用户ID
      responses:
        '200':
          description: 获取成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  code:
                    type: integer
                    example: 0
                  message:
                    type: string
                    example: "success"
                  data:
                    type: object
                    properties:
                      id:
                        type: integer
                      username:
                        type: string
                      email:
                        type: string
                      phone:
                        type: string
                        nullable: true
                      status:
                        type: string
                        enum: [active, inactive, suspended]
                      created_at:
                        type: string
                        format: date-time
                      updated_at:
                        type: string
                        format: date-time
        '404':
          description: 用户不存在

    put:
      summary: 更新用户信息
      description: 更新用户基本信息，只能修改自己的信息
      tags:
        - 用户管理
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
          description: 用户ID
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                  format: email
                phone:
                  type: string
                  pattern: '^1[3-9]\d{9}$'
                avatar:
                  type: string
                  format: uri
                  description: 头像URL
      responses:
        '200':
          description: 更新成功
        '400':
          description: 参数错误
        '403':
          description: 无权限（不能修改他人信息）
        '409':
          description: 邮箱或手机号已存在

  /api/users:
    get:
      summary: 查询用户列表
      description: 分页查询用户列表，支持多种筛选条件
      tags:
        - 用户管理
      parameters:
        - name: page
          in: query
          schema:
            type: integer
            minimum: 1
            default: 1
          description: 页码
        - name: page_size
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
          description: 每页数量
        - name: status
          in: query
          schema:
            type: string
            enum: [active, inactive, suspended]
          description: 用户状态筛选
        - name: keyword
          in: query
          schema:
            type: string
            maxLength: 50
          description: 搜索关键词（用户名、邮箱）
        - name: sort_by
          in: query
          schema:
            type: string
            enum: [id, username, created_at]
            default: id
          description: 排序字段
        - name: sort_order
          in: query
          schema:
            type: string
            enum: [asc, desc]
            default: desc
          description: 排序方式
      responses:
        '200':
          description: 查询成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  code:
                    type: integer
                    example: 0
                  message:
                    type: string
                    example: "success"
                  data:
                    type: object
                    properties:
                      total:
                        type: integer
                        description: 总记录数
                      page:
                        type: integer
                        description: 当前页码
                      page_size:
                        type: integer
                        description: 每页数量
                      list:
                        type: array
                        items:
                          type: object
                          properties:
                            id:
                              type: integer
                            username:
                              type: string
                            email:
                              type: string
                            status:
                              type: string
                            created_at:
                              type: string
                              format: date-time

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

  schemas:
    Error:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: integer
          description: 错误码
        message:
          type: string
          description: 错误信息
        details:
          type: object
          description: 详细错误信息
          nullable: true

security:
  - BearerAuth: []


path: examples/simple-example.md
content: # 简化接口定义示例

## 示例1：用户注册接口

```
接口名称: 用户注册
接口路径: POST /api/users/register
请求参数:
  - username: string, 必填, 3-20字符, 字母数字下划线
  - [REDACTED_SECRET], 必填, 6-20字符, 必须包含字母和数字
  - email: string, 必填, 邮箱格式
  - phone: string, 可选, 11位手机号
  - invite_code: string, 可选, 6位邀请码
返回字段:
  - id: integer
  - username: string
  - email: string
  - [REDACTED_SECRET]
  - created_at: datetime
业务规则:
  - 用户名不能重复
  - 邮箱不能重复
  - 手机号不能重复（如提供）
  - 邀请码必须有效（存在于系统中）
```

## 示例2：用户登录接口

```
接口名称: 用户登录
接口路径: POST /api/users/login
请求参数:
  - account: string, 必填, 用户名、邮箱或手机号
  - [REDACTED_SECRET], 必填, 密码
  - remember_me: boolean, 可选, 记住登录状态
返回字段:
  - user: object
    - id: integer
    - username: string
    - email: string
    - phone: string
  - [REDACTED_SECRET]
  - expires_in: integer
业务规则:
  - 密码错误5次锁定账号30分钟
  - token有效期24小时（remember_me=false）或7天（remember_me=true）
```

## 示例3：查询用户列表

```
接口名称: 查询用户列表
接口路径: GET /api/users
请求参数:
  - page: integer, 可选, 页码, 默认1, 最小1
  - page_size: integer, 可选, 每页数量, 默认20, 最小1, 最大100
  - status: enum, 可选, [active, inactive, suspended]
  - keyword: string, 可选, 搜索关键词, 最大50字符
  - sort_by: enum, 可选, [id, username, created_at], 默认id
  - sort_order: enum, 可选, [asc, desc], 默认desc
返回字段:
  - total: integer
  - page: integer
  - page_size: integer
  - list: array
    - id: integer
    - username: string
    - email: string
    - status: string
    - created_at: datetime
业务规则:
  - 只能查看有权限的用户数据
  - 支持模糊搜索用户名和邮箱
  - 按指定字段排序
```

## 示例4：创建订单接口

```
接口名称: 创建订单
接口路径: POST /api/orders
请求参数:
  - user_id: integer, 必填, 用户ID
  - product_ids: array, 必填, 商品ID列表
  - address_id: integer, 必填, 地址ID
  - coupon_code: string, 可选, 优惠券代码
  - remark: string, 可选, 备注, 最大200字符
返回字段:
  - order_id: string
  - order_number: string
  - total_amount: number
  - status: string
  - created_at: datetime
业务规则:
  - 用户必须存在且状态正常
  - 商品必须存在且有库存
  - 地址必须存在且属于该用户
  - 优惠券必须有效且未过期
  - 订单金额必须大于0
  - 单个用户同一时间最多5个未支付订单
```

## 示例5：文件上传接口

```
接口名称: 上传头像
接口路径: POST /api/users/avatar
请求参数:
  - user_id: integer, 必填, 用户ID
  - file: file, 必填, 图片文件
  - file_type: enum, 必填, [jpg, png, gif]
返回字段:
  - url: string
  - filename: string
  - size: integer
  - upload_time: datetime
业务规则:
  - 只能上传自己的头像
  - 文件大小不能超过2MB
  - 支持JPG、PNG、GIF格式
  - 上传后自动删除旧头像
```

## 格式说明

### 接口基本信息

```
接口名称: [接口的中文名称]
接口路径: [HTTP方法] [URL路径]
```

### 请求参数

```
请求参数:
  - [参数名]: [类型], [必填/可选], [约束条件], [描述]
```

**类型支持**：string, integer, number, boolean, array, object, file, enum

**约束条件**：
- 字符串：长度范围（如3-20字符）、正则表达式（如字母数字下划线）、格式（如邮箱）
- 数字：取值范围（如0-150）、精度
- 数组：元素类型、元素数量
- 对象：嵌套字段定义（缩进表示层级）
- 枚举：有效值列表（如[active, inactive, suspended]）

### 返回字段

```
返回字段:
  - [字段名]: [类型]
  - [字段名]: [类型]
    - [子字段]: [类型]  # 对象类型
  - [字段名]: array
    - [元素字段]: [类型]  # 数组元素类型
```

### 业务规则

```
业务规则:
  - [规则描述]
  - [规则描述]
```

常见的业务规则：
- 唯一性：用户名不能重复
- 存在性：用户必须存在
- 状态：只有审核通过的才能操作
- 权限：只能操作自己的数据
- 数量：最多创建10个
- 关联：订单必须关联有效的用户

## 使用脚本生成

```bash
# 从简化定义生成
python scripts/generate-checklist.py \
  --input examples/simple-example.md \
  --format simple \
  --output output/checklist.md

# 从字符串生成
python scripts/generate-checklist.py \
  --input "接口名称: 测试接口
接口路径: POST /api/test
请求参数:
  - name: string, 必填
返回字段:
  - id: integer" \
  --format simple
```


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)