API 自动化测试
铁律:不得以“契约已导入”代替自动化执行,也不得为追求覆盖率而绕过目标环境、写操作或 secret 安全门禁。
把一次用户请求视为一个完整任务。按需完成接口发现、定义导入、测试选择、自动化执行和结果总结,不向用户暴露内部模块交接。契约驱动是实现手段,不是公开能力边界;自动化能力不得只停留在 schema 检查。
核心原则
不得静默丢弃来源语义。OpenAPI/Swagger 必须保留全部字段和原版本;YApi/Postman 只要有损,就必须先写入 source-manifest.json,再生成或执行测试。
默认执行采用双轨:
- Arazzo 1.1 声明式 workflow 覆盖登录、响应提取、跨步骤变量、业务断言、setup、cleanup 和数据驱动。
- Schemathesis 覆盖 examples、coverage、fuzzing 和 stateful property-based 测试。
已有 Python 测试资产或 Arazzo 无法安全表达的专用验证,才使用受控 pytest 兼容入口。pytest collection 和 execution 都会加载用户 Python 代码,必须显式限定项目目录和 selector;不得把它描述成静态扫描,也不得用 pytest 取代默认双轨。
不要把登录或 cleanup 藏在任意 Python/JavaScript 中。需要理解选型依据时读取 community-practices.md。
执行清单
-
- 识别用户意图、输入格式/版本和目标环境。
-
- inspect 来源;需要写入时再 import,已有产物未经
--force不覆盖。
- inspect 来源;需要写入时再 import,已有产物未经
-
- 选择确定性 workflow、Schemathesis、受控 pytest 兼容,或先 workflow 后 schema 的双轨执行。
-
- 在首个网络请求前校验 secret、报告路径、operation 引用和写操作确认。
-
- 执行所选测试;cleanup 必须覆盖失败路径。
-
- 校验脱敏结果和退出状态,再按交付检查总结。
按意图选择路径
不得强迫所有请求经过固定阶段:
- 纯分析:检查来源并报告 operation 清单、保真度和风险。
- 导入:先检查,再写规范化描述和来源 manifest。
- 明确源码扫描:使用源码 adapter,并复核 OpenAPI 骨架。
- 执行现有定义:先确认目标安全,再运行所选模式。
- 运行已有 pytest:显式 collection,复核 source manifest,再按原生 nodeid 精确执行。
- 端到端:在同一任务中完成导入与执行,再总结规范化结果。
所有路径都必须先识别来源,再写入文件;执行前复核 warning 和 unsupported feature;secret 只放环境变量;配置错误与测试发现必须分开。只有用户要求纯分析时才停在检查阶段。
来源处理
识别或转换来源时读取 source-formats.md。
写项目文件前先检查:
python <skill-dir>/scripts/import_api.py inspect <file-or-url>
导入文件、原始 spec URL 或 Swagger UI URL:
python <skill-dir>/scripts/import_api.py import <file-or-url> \
--output-dir <project>/api-tests
通过 YApi Open API 导入项目:
YAPI_TOKEN=<secret> python <skill-dir>/scripts/import_api.py import \
--yapi-base-url https://yapi.example.invalid \
--yapi-project-id 123 \
--output-dir <project>/api-tests
只有用户明确要求扫描代码时才扫描本地后端:
python <skill-dir>/scripts/import_api.py inspect --code-root <backend-dir>
python <skill-dir>/scripts/import_api.py import --code-root <backend-dir> \
--output-dir <project>/api-tests
需要限制路径时使用 --code-prefix /api。不得推断 code root、默认扫描当前仓库、导入应用模块或执行应用代码。普通目录作为位置参数时,不得视为源码扫描请求。
YApi token 必须通过环境变量传入,不得出现在命令、产物、日志或回复中;不得抓取 YApi HTML。
除 import_api.py、run_api.py、run_workflows.py、run_automation.py、pytest_compat.py、migrate_legacy_cases.py 外,其余 scripts/*.py 都是这些入口复用的内部模块,不直接作为公共命令调用。
导入产物:
openapi.yaml:原样语义保留的 OpenAPI/Swagger、从 YApi/Postman 规范化的 OpenAPI 3.1,或明确源码扫描产生的待复核 OpenAPI 3.1 路由骨架。source-manifest.json:来源 hash、格式/版本、保真度、警告、不支持能力和 operation 数量。
YApi/Postman 转换不得标为无损。源码扫描必须标为 skeleton,保留 operation 级来源信息,不得发明请求/响应 schema、状态码或认证规则。不支持的脚本只记录警告,不得执行。
自动化测试选择与执行
执行测试或处理认证前读取 execution.md。
只做契约广覆盖时使用 Schemathesis:
python <skill-dir>/scripts/run_api.py <project>/api-tests/openapi.yaml \
--url <base-url> \
--mode smoke \
--output <project>/api-tests/reports/run-result.json
模式:
smoke:examples + coverage;未确认写入权限时只选择 GET/HEAD/OPTIONS/TRACE。full:examples + coverage + fuzzing + stateful;仅用于隔离测试环境。stateful:只跑 operation chain;可能创建、修改或删除共享数据时必须明确确认。
使用 --header-env HEADER=ENV_VAR 注入 secret;缺少环境变量时必须在联网前失败。只有用户需要 Allure 时才使用 --allure-results <dir>。
生产环境不得运行生成式负向、fuzzing 或 stateful 测试。环境身份不明时,只做安全检查和导入,然后请求确认目标。
确定性业务旅程使用 Arazzo sidecar:
python <skill-dir>/scripts/run_workflows.py <project>/api-tests/workflow.yaml \
--schema <project>/api-tests/openapi.yaml \
--url <base-url> \
--workflow authenticatedUser \
--input username=demo \
--input-env password=API_PASSWORD \
--output <project>/api-tests/reports/workflow-result.json
用 --data cases.csv 或 --data cases.json 批量覆盖 workflow inputs;用 --tag 或 --workflow 选择场景。setup、主步骤和 cleanup 中任何 POST/PUT/PATCH/DELETE 都必须在确认目标后加 --allow-mutating-target,workflow 自身不得绕过该门禁。需要 CI 报告时可加 --junit 或 --allure-results。
登录结果需要继续给 Schemathesis 使用时,执行一体化双轨命令:
python <skill-dir>/scripts/run_automation.py <project>/api-tests/workflow.yaml \
--schema <project>/api-tests/openapi.yaml \
--url <base-url> \
--preflight-workflow loginAndVerify \
--input-env username=API_USERNAME \
--input-env password=API_PASSWORD \
--schema-header-from-output Authorization=token \
--header-template 'Authorization=Bearer {value}' \
--allow-preflight-mutating-target
workflow 必须显式声明供 schema 阶段使用的 output。Runner 只通过临时环境变量传递 secret,结束后立即恢复环境;不得把 output 值写进报告。只有确认生成式测试也可写入目标时,才加 --allow-schema-mutating-target。
运行已有 pytest 资产时读取 pytest-compatibility.md。先 collection 并生成绑定源码指纹的 manifest,再选择 manifest 中的完整 nodeid 执行:
python <skill-dir>/scripts/pytest_compat.py collect <pytest-project> \
--selector tests/api \
--output <project>/api-tests/pytest-source-manifest.json
python <skill-dir>/scripts/pytest_compat.py run <pytest-project> \
--manifest <project>/api-tests/pytest-source-manifest.json \
--nodeid 'tests/api/test_users.py::test_get_user[active]' \
--junit <project>/api-tests/reports/pytest-junit.xml \
--output <project>/api-tests/reports/pytest-run-result.json
默认设置 PYTEST_DISABLE_PLUGIN_AUTOLOAD=1;只有项目明确声明所需插件时,collection 才可重复使用 --plugin。source manifest 过期、未知 nodeid、零选择、collection error、JUnit 损坏或 pytest 版本变化都必须作为配置错误失败关闭。pytest exit code 是结果权威来源,JUnit 只提供结构化 testcase 证据。
迁移旧版 project.yaml + flows/ + cases/:
python <skill-dir>/scripts/migrate_legacy_cases.py \
--project <legacy>/project.yaml \
--schema <project>/api-tests/openapi.yaml \
--output <project>/api-tests/workflow.yaml \
--manifest <project>/api-tests/legacy-migration.json
迁移支持 YAML、JSON、CSV、XLSX,保留 flow、setup/steps/teardown、标签、环境/项目变量、默认 header、提取和 eq/ne/数值/contains/exists 断言。遇到无法无损表达的旧语义必须以 conversion 错误停止,不得写部分 workflow。
面向用户的 CLI 只有 import_api.py、run_api.py、run_workflows.py、run_automation.py、pytest_compat.py 和 migrate_legacy_cases.py;其余 scripts/ 文件是内部模块。agents/、evals/ 和 tests/ 只供维护、评测与回归验证,不作为用户工作流入口。
项目与结果契约
写项目文件、解释保真度或消费 run-result.json 时读取 contracts.md。
- OpenAPI/Swagger 负责 HTTP surface 和 schema。
- Arazzo workflow 用唯一
operationId引用 operation,负责确定性业务旅程。 - 环境 profile 只保存非敏感配置。
- 凭证由环境变量或 secret provider 管理。
- JSON 结果是正式数据;JUnit/Allure 只是 reporter。
- pytest source manifest 绑定 collection 时的 nodeid、pytest 版本、配置和源码指纹;运行结果同时保留原始 exit code 与脱敏 JUnit 证据。
失败分类
推荐修改前先分类:
source:输入不可读、格式/版本不支持或文档损坏。conversion:来源能力无法安全映射到 OpenAPI。configuration:缺少 base URL、工具、secret 或参数非法。collection:pytest collection 加载失败、零用例或 selector 不合法。transport:DNS、TLS、连接或超时。contract:状态码、content type、header 或 response schema 不匹配。behavior:业务断言或状态迁移失败。cleanup:测试状态创建后无法清理。
不得为了让实现通过而改写源契约。展示证据,并说明更可能过期的是契约还是实现。
禁止的捷径
- 不因发现 OpenAPI 就默认扫描源码或执行接口。
- 不执行 Postman/JavaScript/Python 任意脚本来补登录或断言;用户显式选择的存量 pytest 项目只能通过 source manifest 和 nodeid 门禁执行。
- 不把 secret 放进命令参数、数据集、workflow、报告或回复。
- 不把配置/transport error 记成测试发现,也不把失败的 cleanup 记成通过。
- 不在未确认目标时用
--force、写方法、fuzzing 或 stateful 扩大影响面。
交付检查
- 说明输入类型与版本。
- 说明导入是
lossless、high、high-with-losses还是源码skeleton。 - 列出警告和不支持能力,不得隐藏空导入或部分导入。
- 列出实际写入文件。
- 说明是否真的执行了网络测试以及非敏感 base URL。
- 说明模式、结果路径、pass/fail/error 状态和可行动失败类别。
- 使用 pytest 时说明 collection 会执行 Python、选择的 nodeid、manifest 指纹状态、原始 exit code 和插件列表。
- 说明有意未执行的活动。