api-testing
接口级测试时使用——从 OpenAPI/Swagger 文档或用例 Schema 中可自动化的接口用例出发,覆盖参数、边界、鉴权、幂等、并发、错误响应与数据一致性,产出可执行的 API 测试脚本与运行结果;含接口压测承接(k6,类型矩阵轴 1 执行层)。不用于:Web UI 流程(automated-e2e-testing)、手动用例编写(test-case-writing)。
Install
npx skills add https://github.com/fishzjp/qa-skills/tree/main/skills/api-testing
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install fishzjp-qa-skills@llmmart
git clone https://github.com/fishzjp/qa-skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole fishzjp/qa-skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
API 测试(api-testing)
接口级测试——E2E 之外的另一条执行路径。
- 输入:API 文档(OpenAPI/Swagger)、用例 Schema 中
execution_model可自动化的接口用例、被测环境信息(base URL、账号/Token);性能轴(类型矩阵轴 1)移交包专项移交_性能_*.yaml - 输出(落盘):API 测试脚本(pytest + requests,或项目既定技术栈)+ 执行分报告
测试报告_api_{日期}.md(命名按../core/report-template.md头注,条目按其 §3 对齐;qa 断点判据按此文件名核收);性能承接时另产 k6 压测脚本与压测报告(references/k6-conventions.md) - 边界:Web UI 流程 →
automated-e2e-testing;接口手动用例设计 →test-case-writing
When to Use
- 给定 OpenAPI/Swagger 文档,需要产出并运行接口自动化测试
- 从用例 Schema 中筛出接口级可自动化用例,转换为 API 脚本执行
- 需要覆盖鉴权/越权、幂等、并发写、错误响应等接口层专项
- 给定性能移交包或接口清单,需要生成并运行压测脚本(k6)——按
references/k6-conventions.md
When NOT to Use
- Web UI 交互流程(点击 / 页面状态)→
automated-e2e-testing - 编写接口的手动测试用例 →
test-case-writing - 端到端流水线 →
qa编排 - 独立压测环境搭建与容量保障 → 运维/专项协作(agent 侧压测承接见
references/k6-conventions.md;外部执行场景按test-strategy的移交包) - Mock Server 搭建 → 开发协作事项,不在本 skill 范围
脚手架(默认 pytest + requests,可替换为项目既定栈)
api-tests/
├── conftest.py # fixture:base_url、会话/Token、环境配置(环境变量注入,可由 .env 加载,不硬编码)
├── common/
│ └── client.py # 统一请求封装:日志、超时、鉴权头、断言辅助
├── test_{模块}_{接口}.py # 一个接口一个文件,test 名沿用 TC 编号
└── requirements.txt
# common/client.py —— 统一请求封装(requests.Session 不支持 base_url,必须显式拼接)
import requests
class Client:
def __init__(self, base_url: str, token: str):
self.base_url = base_url.rstrip("/")
self.s = requests.Session()
self.s.headers.update({"Authorization": f"Bearer {token}"})
def request(self, method: str, path: str, **kwargs):
url = f"{self.base_url}/{path.lstrip('/')}"
kwargs.setdefault("timeout", 10)
return self.s.request(method, url, **kwargs)
def get(self, path, **kw): return self.request("GET", path, **kw)
def post(self, path, **kw): return self.request("POST", path, **kw)
# put / delete / patch 同理扩展
def login(user: str, password: str) -> str:
"""按项目实际登录接口实现(如 POST /login 换 token)——占位,勿直接照抄"""
raise NotImplementedError("按项目登录接口实现")
# conftest.py 关键 fixture
import os
import pytest
from common.client import Client, login
@pytest.fixture(scope="session")
def client():
base_url = os.environ["API_BASE_URL"] # 环境与账号不硬编码,走环境变量
token = login(os.environ["API_USER"], os.environ["API_PASSWORD"])
return Client(base_url, token)
敏感信息(账号/Token/环境地址)一律环境变量注入,不进代码仓库(与
automated-e2e-testing的 constants 约定一致)。
工作流
1. 输入解析与范围确认
- 从 OpenAPI 文档提取:接口清单、参数表(必填/类型/范围/默认值)、错误码、鉴权方式
- 从用例 Schema 过滤:
automation.framework: api的用例,以及execution_model: dev-collab且 framework 非 manual 的用例 → 转换对象(test 名沿用 TC 编号:test_TC_05_01_写入字段读回一致;framework: manual 的 dev-collab 用例保持手动协作,不转) - 环境未知 → 向用户索取(base URL、账号、是否可写生产旁路环境),不确定就问,不猜接口行为(提问格式与裁决落盘统一按
../core/clarify-pattern.md,场景用「执行确认」)
2. 用例设计(此时加载 ../core/testing-principles.md,方法细节 ../core/methods/data-driven.md)
每接口一张参数矩阵(分析过程工具,心内构建或草稿即可,不落盘为中间文件——结论直接进用例,与 test-case-writing 的无中间文件口径一致),逐参数 × 逐属性;重点覆盖:
| 类别 | 必测点 |
|---|---|
| 参数 | 必填缺失 / 类型错误 / 边界值(空/最值/超大,见 ../core/methods/boundary.md) |
| 鉴权 | 无 Token / 过期 Token / 错误 Token / 越权(他人资源 id)——越权方法基线 ../core/methods/permission.md(Role×Action×Resource 矩阵 + 垂直/水平两类越权,即类型矩阵轴 2 的执行层) |
| 幂等 | 同一业务键重复提交 → 不重复创建;重试安全 |
| 并发 | 并发写同一资源 → 无互相覆盖、无中间态 |
| 错误响应 | 每个错误码的触发条件 + 响应体结构与文案 |
| 数据一致性 | 写后读回一致;级联操作后关联数据一致 |
多参数接口的组合面按 ../core/methods/data-driven.md 第 2 节显式降档执行(全组合 → 成对组合 → 风险挑选):单参数逐属性做全;跨参数交互(跨字段规则 / 参数依赖)选档覆盖,成对组合为默认档;降档与被排除的组合面写进 rationale,不静默收缩。
3. 脚本编写
- 一个接口一个 test 文件;一条 test 只测一个点,沿用 TC 编号命名
- 输出预算纪律(防空截断):同类边界/参数校验用
@pytest.mark.parametrize合并为一条参数化测试,禁止逐值展开重复的 test 函数或超长重复断言——单文件超过 ~250 行即应参数化收敛(生成通道有输出上限,超限会截断产生不可编译代码) - 断言三件套:状态码 + 业务码 + 响应体关键字段(不写"只断言 200"的弱断言)
- 测试数据自建自清理(setup 创建 / teardown 删除),不依赖执行顺序;数据模板(唯一名等)先核对材料字段约束(maxLength/枚举/格式),模板总长(前缀+随机段)≤ 约束上限 −2——顶格即数据自建缺陷(实测自伤案例:唯一名模板 22 字符撞契约 maxLength 20;两个实测案例与 test-case-writing §4 各存同源副本,修订须两处同步);参数矩阵逐格回检跨字段业务规则(如"使用门槛不能低于面额")——违反规则的组合改取合法值或拆为显式负向用例,不做隐式非法组合(实测自伤案例:金额顶格 1000 配低于面额的门槛 → 400 THRESHOLD_INVALID 而用例期望 201)
- 依赖前序状态的用例显式在前置里造数,不假设库里有数据(造数模式:
../core/methods/data-factory.md——makeX 构造器 / 造数通道三选一 / 前缀隔离)
4. 运行与结果
报告条目与统计口径以 ../core/report-template.md 为唯一来源(含机读摘要片段,收尾时加载),保证可直接拼装进 qa 收尾的最终报告:
pytest api-tests/ -v --tb=short # 全量
pytest api-tests/test_coupon_create.py # 单文件
- 失败用例先分辨:被测系统 Bug / 环境问题 / 用例自身错误——不自行假设,环境问题与预期歧义列出来问用户(提问格式同上,
../core/clarify-pattern.md) - 失败 ≥3 条时升级为批量分流:先按
../core/triage.md四分类定类(A 真缺陷 / B 资产问题〔B1 产品预期变更・B2 用例自身错误〕/ C 环境与依赖故障 / D 不稳定),仅 A 类进入下方 Bug 记录流程,替换单条逐个分辨 - 流水线运行:以 headless 模式进入 PR 冒烟 / 夜间任务时,检查点降级为未决项、产物按规范落盘、退出码分离基建故障与真缺陷——三条约定见
../core/pipeline-integration.md(此时加载) - 结构覆盖补充证据(可选):有被测服务代码且测试环境可插桩(Python 服务
coverage run启动;JVM 服务 JaCoCo agent)时,接口用例跑完取被测服务的行/分支覆盖率作为补充 E3 证据——只用于发现零覆盖/极低覆盖的接口与分支(漏测信号,转补用例或策略升档),不作为追高的虚荣指标;无插桩条件直接跳过,不阻塞交付 - 发现的 Bug:证据(请求/响应原文、时间戳)按
../core/report-template.md§3 记录条目,根因分析移交bug-analysis
5. 交付
脚本路径 + 运行统计(§2 执行统计:P0/P1/P2 × 通过/失败/阻塞/未执行,按 ../core/report-template.md)+ Bug 条目 + 遗留问题清单 + (有插桩时)结构覆盖摘要:零覆盖/低覆盖接口清单。
契约与 schema 一致性(类型矩阵轴 10 执行层)
轴 10 决策 include 时按本节执行(决策与档位来自 test-strategy 的 type_scope,本节只管执行形态);报告回收走 report-template §7 表,执行方列如实填写。
两层形态(分工不互替)
| 层 | 对象 | 做法 |
|---|---|---|
| schema 一致性 | 响应体 vs OpenAPI 定义逐字段(类型/必填/枚举) | Schemathesis 一条命令接入:schemathesis run openapi.yaml --base-url $API_BASE_URL;或手写 jsonschema 断言并入现有 test 文件 |
| 结构级负向 fuzzing | 结构鲁棒性(类型错位 / 超长 / 格式畸变) | Schemathesis 自动生成非法输入。与 §2 参数矩阵分工:矩阵管业务语义组合,fuzzing 管结构鲁棒性 |
概念边界
- schema 校验 ≠ 消费者契约:schema 只验"响应符合定义",契约验"消费者-提供者允许的交互集合"
- Pact 式消费者驱动契约的启用判据:多消费者微服务且字段演进频繁——单系统项目 schema 一致性即可,不上契约框架
- 契约执行物按 type_scope 进执行策略裁决(脚本型消费方式);mock/沙箱依赖不可得按矩阵 R5 记 blocked
执行纪律
- fuzzing 发现的 5xx / 未定义错误码视为候选缺陷,逐条归因(与 §4 失败分辨同流程),不自动记 Bug
- schema 校验全过 ≠ 契约没问题:字段语义变更(结构未变)schema 层不可见,语义回归靠业务用例
Common Mistakes
| 错误 | 后果 | 正确做法 |
|---|---|---|
| 只断言状态码不断言业务码与响应体 | Bug 漏检(200 但业务失败) | 状态码 + 业务码 + 关键字段三件套 |
| 硬编码环境地址与账号 | 无法跨环境运行、泄露敏感信息 | 环境变量注入 |
| 测试间共享可变状态 | 顺序依赖、偶发失败 | 自建数据 + 自清理,每条独立 |
| 重复提交不测幂等 | 重复创建类 Bug 上线 | 同业务键重复请求必测 |
| 失败一律记为 Bug | 误报污染报告 | 先归因(系统/环境/用例),歧义问用户 |
| 无权限/越权只测前端表现 | 后端未拦截的越权漏检 | 直接调接口测鉴权(无 Token/过期/他人 id) |
| 多参数接口逐值全展开或随手抽样 | 组合爆炸截断 / 参数交互缺陷静默漏测 | 按降档策略显式选档(全组合 → 成对 → 风险挑选),降档留痕 |
| Schema 用例带占位符/虚构入口仍直接翻成脚本 | 幻觉脚本:能跑通但测的不是真实接口 | 转换前过 ../core/executability.md 红线闸门,补不了的暂缓进遗留清单 |
| schema 校验全过就当契约没问题 | 字段语义变更(结构未变)漏检 | schema 只验结构;语义回归靠业务用例(见「契约与 schema 一致性」节) |
Files (qa-skills)
-
references
-
k6-conventions.md 5.3 KB
# k6 压测工程约定(k6-conventions) > `api-testing` 的性能压测执行层,类型矩阵轴 1 决策 include 时的执行形态。两种承接: > **agent 直接承接**(type_scope `executor: agent`,standard 起步)与本文件全程工作; > **移交包承接**(`executor: k6/locust` + handoff_ref)时按移交包的字段与口径执行, > 可顺带产出脚本草稿回写移交包。档位语义(light / standard / full)以 > `../core/test-type-matrix.md` 轴 1 为唯一来源,本文件不为档位发明新语义。 ## 1. 接入与运行 ```bash brew install k6 # 或官方二进制/包管理器,单文件无运行时依赖 k6 run load-xxx.js # 退出码即 thresholds 判定:0 = 全部阈值通过,非 0 = 存在失败 ``` - **退出码对接 pipeline-integration**:thresholds 失败**不是自动 Bug**——默认进 S 级复核 / 未决项通道,归因(环境容量 / 数据 / 脚本缺陷 / 真实回归)之后才可升 A 类; CI 门禁语义是"阻断合入",不是"自动定性为缺陷" - 环境地址与账号走环境变量注入(与 api-testing 主纪律一致),不硬编码 ## 2. 移交包字段 → k6 options 映射 移交包(`专项移交_性能_{日期}.yaml`)三要素逐项映射,缺项先向移交发起方/用户索取(提问格式按 `../core/clarify-pattern.md` 场景「执行确认」): | 移交包字段 | k6 options | 说明 | |---|---|---| | 目标(接口清单) | 各 scenario 的 http 请求定义 | 一个核心接口一个 scenario;标明方法 + 路径 + 鉴权方式 | | 场景参数(并发用户数 / 持续时间 / 阶梯) | `stages` 或 `scenarios` | standard = 单接口阶梯加压;full = 用户旅程 × 到达率 → 多 scenario | | 阈值 / 验收口径 | `thresholds` | p95 / 错误率起步;移交包带口径时按口径,不带时从业务 SLO 推导并向用户确认 | ## 3. 最小脚本模板(standard:单接口阶梯加压) ```javascript import http from 'k6/http'; import { check } from 'k6'; export const options = { stages: [ { duration: '1m', target: 20 }, // 阶梯值来自移交包"场景参数" { duration: '3m', target: 20 }, { duration: '1m', target: 0 }, ], thresholds: { http_req_duration: ['p(95)<500'], // 阈值来自移交包"阈值/验收口径"或 SLO http_req_failed: ['rate<0.01'], }, }; export function setup() { // 登录取 token——复用 api-testing 鉴权纪律:环境变量注入,占位实现按项目实际接口改 const res = http.post(`${__ENV.API_BASE_URL}/login`, JSON.stringify({ user: __ENV.API_USER, password: __ENV.API_PASSWORD, }), { headers: { 'Content-Type': 'application/json' } }); return { token: res.json('token') }; } export default function (data) { const res = http.get(`${__ENV.API_BASE_URL}/api/target`, { headers: { Authorization: `Bearer ${data.token}` }, }); check(res, { '状态码 200': (r) => r.status === 200 }); } ``` ## 4. 档位对接 - **light**:代码级性能审查(分页 / 缓存 / N+1 / 锁,逐项出 E2 证据清单)——矩阵既有语义,无脚本 - **standard**:单接口阶梯加压(第 3 节模板),p95 + 错误率两阈值起步 - **full**:压测模型(用户旅程 × 到达率阶梯)→ `scenarios` 多场景展开(浏览 / 下单 / 支付各按到达率配 `constant-arrival-rate` 或 `ramping-arrival-rate`),每场景独立 thresholds;产出瓶颈归因报告(慢在哪个接口 / 哪类资源,E3 证据 = summary 原文) ## 5. 触发分层对接(pipeline-integration) | 层级 | 压测动作 | |---|---| | PR 冒烟 | 不跑压测(快失败 <10 分钟,压测不进 P0) | | 夜间全量 | standard 档压测(阈值失败走 S 级复核,不直接红灯定性) | | 发布卡点 | full 档(类型矩阵 full 轴范围),thresholds 失败阻断发布 + 归因 | ## 6. 结果回收 - `k6 run` 末尾的 end-of-test summary 是回收源:截取指标块 + 阈值判定落 `{项目}/压测报告_{日期}.md` - 回填 `../core/report-template.md` §7 表:执行方列如实填 `k6`,结果摘要含 "指标 / 阈值 / 通过与否",产物路径指向压测报告 - **移交承接场景**:按移交包"阈值/验收口径"判定后回填;执行前提不可得(无独立环境 / 数据不可重置)时按矩阵 R5 记 blocked + todo,不静默跳过 - 移交承接时可附 k6 脚本草稿:脚本路径写回移交包(optional 字段),把"移交不断链" 升级为"移交可执行" ## 7. 处置纪律 - **基准先行**:正式加压前先跑一次短程基准(1 VU × 30s)测当前水位——阈值不拍脑袋, 从 SLO 或移交包口径推导,与基准差距异常先查环境 - **前置确认**(「执行确认」):压测环境是否独立(不打生产 / 不与同事共用环境)、 数据是否可重置、能打多大压力——三问清了再开压 - **基准噪音控制**:矩阵轴 1 成本因子——共用环境的干扰流量会让基准失真,结论里声明环境状况 - **压测不达标 ≠ Bug**:先归因(环境容量 / 数据 / 脚本缺陷 / 真实回归),归因依据落 报告后才可进缺陷流程 - **压测安全**:阶梯值不自行放大——移交包/用户给多少就压多少,"多压一点看看极限" 必须先问
-
-
SKILL.md 12.1 KB
--- name: api-testing slug: api-testing displayName: API 接口测试 version: 0.8.1 description: "API testing from OpenAPI/Swagger or case schemas: parameters, boundaries, auth, idempotency, concurrency, error responses, data consistency; runnable scripts; k6 handoff. Not for: Web UI flows, manual case writing. 接口级测试:参数/边界/鉴权/幂等/并发/错误响应/数据一致性,产出脚本与结果;含 k6 压测。不用于:Web UI、手动用例。" --- # API 测试(api-testing) 接口级测试——E2E 之外的另一条执行路径。 - **输入**:API 文档(OpenAPI/Swagger)、用例 Schema 中 `execution_model` 可自动化的接口用例、被测环境信息(base URL、账号/Token);性能轴(类型矩阵轴 1)移交包 `专项移交_性能_*.yaml` - **输出(落盘)**:API 测试脚本(pytest + requests,或项目既定技术栈)+ 执行分报告 `测试报告_api_{日期}.md`(命名按 `../core/report-template.md` 头注,条目按其 §3 对齐;qa 断点判据按此文件名核收);性能承接时另产 k6 压测脚本与压测报告(`references/k6-conventions.md`) - **边界**:Web UI 流程 → `automated-e2e-testing`;接口手动用例设计 → `test-case-writing` ## When to Use - 给定 OpenAPI/Swagger 文档,需要产出并运行接口自动化测试 - 从用例 Schema 中筛出接口级可自动化用例,转换为 API 脚本执行 - 需要覆盖鉴权/越权、幂等、并发写、错误响应等接口层专项 - 给定性能移交包或接口清单,需要生成并运行压测脚本(k6)——按 `references/k6-conventions.md` ## When NOT to Use - Web UI 交互流程(点击 / 页面状态)→ `automated-e2e-testing` - 编写接口的手动测试用例 → `test-case-writing` - 端到端流水线 → `qa` 编排 - 独立压测环境搭建与容量保障 → 运维/专项协作(agent 侧压测承接见 `references/k6-conventions.md`;外部执行场景按 `test-strategy` 的移交包) - Mock Server 搭建 → 开发协作事项,不在本 skill 范围 ## 脚手架(默认 pytest + requests,可替换为项目既定栈) ```text api-tests/ ├── conftest.py # fixture:base_url、会话/Token、环境配置(环境变量注入,可由 .env 加载,不硬编码) ├── common/ │ └── client.py # 统一请求封装:日志、超时、鉴权头、断言辅助 ├── test_{模块}_{接口}.py # 一个接口一个文件,test 名沿用 TC 编号 └── requirements.txt ``` ```python # common/client.py —— 统一请求封装(requests.Session 不支持 base_url,必须显式拼接) import requests class Client: def __init__(self, base_url: str, token: str): self.base_url = base_url.rstrip("/") self.s = requests.Session() self.s.headers.update({"Authorization": f"Bearer {token}"}) def request(self, method: str, path: str, **kwargs): url = f"{self.base_url}/{path.lstrip('/')}" kwargs.setdefault("timeout", 10) return self.s.request(method, url, **kwargs) def get(self, path, **kw): return self.request("GET", path, **kw) def post(self, path, **kw): return self.request("POST", path, **kw) # put / delete / patch 同理扩展 def login(user: str, password: str) -> str: """按项目实际登录接口实现(如 POST /login 换 token)——占位,勿直接照抄""" raise NotImplementedError("按项目登录接口实现") ``` ```python # conftest.py 关键 fixture import os import pytest from common.client import Client, login @pytest.fixture(scope="session") def client(): base_url = os.environ["API_BASE_URL"] # 环境与账号不硬编码,走环境变量 token = login(os.environ["API_USER"], os.environ["API_PASSWORD"]) return Client(base_url, token) ``` > 敏感信息(账号/Token/环境地址)一律环境变量注入,不进代码仓库(与 `automated-e2e-testing` 的 constants 约定一致)。 ## 工作流 ### 1. 输入解析与范围确认 - 从 OpenAPI 文档提取:接口清单、参数表(必填/类型/范围/默认值)、错误码、鉴权方式 - 从用例 Schema 过滤:`automation.framework: api` 的用例,以及 `execution_model: dev-collab` 且 framework 非 manual 的用例 → 转换对象(test 名沿用 TC 编号:`test_TC_05_01_写入字段读回一致`;framework: manual 的 dev-collab 用例保持手动协作,不转) - 环境未知 → 向用户索取(base URL、账号、是否可写生产旁路环境),**不确定就问,不猜接口行为**(提问格式与裁决落盘统一按 `../core/clarify-pattern.md`,场景用「执行确认」) ### 2. 用例设计(此时加载 `../core/testing-principles.md`,方法细节 `../core/methods/data-driven.md`) 每接口一张参数矩阵(**分析过程工具,心内构建或草稿即可,不落盘为中间文件**——结论直接进用例,与 test-case-writing 的无中间文件口径一致),逐参数 × 逐属性;重点覆盖: | 类别 | 必测点 | |------|--------| | 参数 | 必填缺失 / 类型错误 / 边界值(空/最值/超大,见 `../core/methods/boundary.md`) | | 鉴权 | 无 Token / 过期 Token / 错误 Token / 越权(他人资源 id)——越权方法基线 `../core/methods/permission.md`(Role×Action×Resource 矩阵 + 垂直/水平两类越权,即类型矩阵轴 2 的执行层) | | 幂等 | 同一业务键重复提交 → 不重复创建;重试安全 | | 并发 | 并发写同一资源 → 无互相覆盖、无中间态 | | 错误响应 | 每个错误码的触发条件 + 响应体结构与文案 | | 数据一致性 | 写后读回一致;级联操作后关联数据一致 | 多参数接口的组合面按 `../core/methods/data-driven.md` 第 2 节**显式降档**执行(全组合 → 成对组合 → 风险挑选):单参数逐属性做全;跨参数交互(跨字段规则 / 参数依赖)选档覆盖,**成对组合为默认档**;降档与被排除的组合面写进 rationale,不静默收缩。 ### 3. 脚本编写 - 一个接口一个 test 文件;一条 test 只测一个点,沿用 TC 编号命名 - **输出预算纪律(防空截断)**:同类边界/参数校验用 `@pytest.mark.parametrize` 合并为一条参数化测试,禁止逐值展开重复的 test 函数或超长重复断言——单文件超过 ~250 行即应参数化收敛(生成通道有输出上限,超限会截断产生不可编译代码) - 断言三件套:状态码 + 业务码 + 响应体关键字段(不写"只断言 200"的弱断言) - 测试数据自建自清理(setup 创建 / teardown 删除),不依赖执行顺序;数据模板(唯一名等)先核对材料字段约束(maxLength/枚举/格式),模板总长(前缀+随机段)≤ 约束上限 −2——顶格即数据自建缺陷(实测自伤案例:唯一名模板 22 字符撞契约 maxLength 20;两个实测案例与 test-case-writing §4 各存同源副本,修订须两处同步);**参数矩阵逐格回检跨字段业务规则**(如"使用门槛不能低于面额")——违反规则的组合改取合法值或拆为显式负向用例,不做隐式非法组合(实测自伤案例:金额顶格 1000 配低于面额的门槛 → 400 THRESHOLD_INVALID 而用例期望 201) - 依赖前序状态的用例显式在前置里造数,不假设库里有数据(造数模式:`../core/methods/data-factory.md`——makeX 构造器 / 造数通道三选一 / 前缀隔离) ### 4. 运行与结果 报告条目与统计口径以 `../core/report-template.md` 为唯一来源(含机读摘要片段,收尾时加载),保证可直接拼装进 `qa` 收尾的最终报告: ```bash pytest api-tests/ -v --tb=short # 全量 pytest api-tests/test_coupon_create.py # 单文件 ``` - 失败用例先分辨:被测系统 Bug / 环境问题 / 用例自身错误——**不自行假设**,环境问题与预期歧义列出来问用户(提问格式同上,`../core/clarify-pattern.md`) - 失败 ≥3 条时升级为**批量分流**:先按 `../core/triage.md` 四分类定类(A 真缺陷 / B 资产问题〔B1 产品预期变更・B2 用例自身错误〕/ C 环境与依赖故障 / D 不稳定),仅 A 类进入下方 Bug 记录流程,替换单条逐个分辨 - **流水线运行**:以 headless 模式进入 PR 冒烟 / 夜间任务时,检查点降级为未决项、产物按规范落盘、退出码分离基建故障与真缺陷——三条约定见 `../core/pipeline-integration.md`(此时加载) - **结构覆盖补充证据(可选)**:有被测服务代码且测试环境可插桩(Python 服务 `coverage run` 启动;JVM 服务 JaCoCo agent)时,接口用例跑完取**被测服务的行/分支覆盖率**作为补充 E3 证据——只用于发现**零覆盖/极低覆盖的接口与分支**(漏测信号,转补用例或策略升档),不作为追高的虚荣指标;无插桩条件直接跳过,不阻塞交付 - 发现的 Bug:证据(请求/响应原文、时间戳)按 `../core/report-template.md` §3 记录条目,根因分析移交 `bug-analysis` ### 5. 交付 脚本路径 + 运行统计(§2 执行统计:P0/P1/P2 × 通过/失败/阻塞/未执行,按 `../core/report-template.md`)+ Bug 条目 + 遗留问题清单 + (有插桩时)结构覆盖摘要:零覆盖/低覆盖接口清单。 ## 契约与 schema 一致性(类型矩阵轴 10 执行层) 轴 10 决策 include 时按本节执行(决策与档位来自 test-strategy 的 type_scope,本节只管执行形态);报告回收走 report-template §7 表,执行方列如实填写。 ### 两层形态(分工不互替) | 层 | 对象 | 做法 | |---|---|---| | schema 一致性 | 响应体 vs OpenAPI 定义逐字段(类型/必填/枚举) | Schemathesis 一条命令接入:`schemathesis run openapi.yaml --base-url $API_BASE_URL`;或手写 jsonschema 断言并入现有 test 文件 | | 结构级负向 fuzzing | 结构鲁棒性(类型错位 / 超长 / 格式畸变) | Schemathesis 自动生成非法输入。与 §2 参数矩阵分工:**矩阵管业务语义组合,fuzzing 管结构鲁棒性** | ### 概念边界 - schema 校验 ≠ 消费者契约:schema 只验"响应符合定义",契约验"消费者-提供者允许的交互集合" - Pact 式消费者驱动契约的启用判据:多消费者微服务且字段演进频繁——单系统项目 schema 一致性即可,不上契约框架 - 契约执行物按 type_scope 进执行策略裁决(脚本型消费方式);mock/沙箱依赖不可得按矩阵 R5 记 blocked ### 执行纪律 - fuzzing 发现的 5xx / 未定义错误码视为候选缺陷,逐条归因(与 §4 失败分辨同流程),不自动记 Bug - schema 校验全过 ≠ 契约没问题:字段语义变更(结构未变)schema 层不可见,语义回归靠业务用例 ## Common Mistakes | 错误 | 后果 | 正确做法 | |------|------|---------| | 只断言状态码不断言业务码与响应体 | Bug 漏检(200 但业务失败) | 状态码 + 业务码 + 关键字段三件套 | | 硬编码环境地址与账号 | 无法跨环境运行、泄露敏感信息 | 环境变量注入 | | 测试间共享可变状态 | 顺序依赖、偶发失败 | 自建数据 + 自清理,每条独立 | | 重复提交不测幂等 | 重复创建类 Bug 上线 | 同业务键重复请求必测 | | 失败一律记为 Bug | 误报污染报告 | 先归因(系统/环境/用例),歧义问用户 | | 无权限/越权只测前端表现 | 后端未拦截的越权漏检 | 直接调接口测鉴权(无 Token/过期/他人 id) | | 多参数接口逐值全展开或随手抽样 | 组合爆炸截断 / 参数交互缺陷静默漏测 | 按降档策略显式选档(全组合 → 成对 → 风险挑选),降档留痕 | | Schema 用例带占位符/虚构入口仍直接翻成脚本 | 幻觉脚本:能跑通但测的不是真实接口 | 转换前过 `../core/executability.md` 红线闸门,补不了的暂缓进遗留清单 | | schema 校验全过就当契约没问题 | 字段语义变更(结构未变)漏检 | schema 只验结构;语义回归靠业务用例(见「契约与 schema 一致性」节) |
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.