---
name: test-scenarios
description: Use this skill when the user asks for a test plan, acceptance criteria, E2E checklist, or auditable scenario contract for a non-trivial change; do not use it for simple single-point edits or as a replacement for implementing tests.
---

# 测试场景契约

## 目标

在代码实现前把“什么行为必须成立”写成可追踪的场景清单，供实现、测试、评审和人工验收共同使用。场景契约描述验收边界，不是把所有测试代码提前写完。

## 何时使用

- 新功能或修复会改变用户、API、配置、数据、任务状态或外部服务行为。
- 变更跨越多个模块，存在边界、兼容性、权限、恢复或失败路径。
- 用户要求测试计划、验收标准、E2E 清单，或需要把验证结果整理成可审计文档。

## 何时不要使用

- 纯拼写、格式、注释或机械重命名。
- 需求和验证方式已经明确，且改动是局部、可逆的单点修改。
- 只需要执行已有测试，不需要新增行为边界。

## 输入与边界

先读取适用的项目指令、现有测试和相邻实现。明确目标、非目标、运行环境、外部依赖和成功标准；事实可以从代码、文档或工具确认时，不要把它们变成用户问题。

如果目标仍有会实质改变结果的歧义，先转交 `brainstorming` 收敛目标，不要在场景表里猜测产品行为。不要因为缺少场景契约就擅自扩大实现范围。

## 最小流程

1. 写下本次变更的目标、非目标、约束和验收入口。
2. 读取现有测试，标记哪些行为已有覆盖，避免把历史测试重新当成新证据。
3. 按需要枚举：主流程、边界输入、错误处理、兼容性、权限/安全、并发/恢复和人工运行面。只保留会改变实现或验收判断的场景。
4. 为每个场景分配稳定 ID、类型、优先级和状态。
5. 将场景写入默认路径 `docs/dev/<run-slug>/test-scenarios.md`；如果已有 ADR，优先放在 ADR 旁边，使用同一个 slug。
6. 实现和验证过程中更新 `covered` 或 `skipped`，并在 `Evidence` 中记录测试路径、命令、日志、资源状态或跳过原因。
7. 如果包含 `e2e` 或 `manual` 场景，补一份短验收指南：准备条件、用户动作、可观察结果、场景 ID 映射，以及哪些结论仍只能由自动化验证证明。

如果用户只要求列出场景而没有授权写文件，直接在回复中输出契约，不创建持久文件。

## 场景契约格式

```markdown
# <任务名> 测试场景

## 范围

- 目标：...
- 非目标：...
- 环境与约束：...
- 角色与权限：...
- 初始条件与测试数据：...
- 外部依赖：...
- 完成后的状态与清理：...

## 场景

| ID | Scenario | Given / When / Then | Type | Priority | Status | Evidence |
|---|---|---|---|---|---|---|
| TS-1 | <短名称> | Given ... / When ... / Then ... | unit/integration/contract/e2e/performance/manual | P0/P1/P2 | todo/covered/skipped | <path, command, result, or reason> |
```

`Given / When / Then` 要描述可观察行为，不要写成实现步骤。`Status` 表示当前证据状态：没有证据保持 `todo`，有可复核证据才标 `covered`，不能验证时标 `skipped` 并写明影响。

## 可追踪性

非平凡或行为变化的任务，补一张从需求到证据的映射表；简单局部改动可在场景表的 `Evidence` 中表达。

```markdown
| Behavior / Requirement | Scenario IDs | Implementation / Test entry | Verify command or runtime evidence | Status |
|---|---|---|---|---|
| <行为或需求> | TS-1, TS-2 | <path:line or test name> | <command, log, URL, or manual record> | todo/covered/skipped |
```

检查两个方向：每个受影响行为都有场景和证据；每个新增测试或实现入口都能说明它保护哪个行为。需求文字发生实质变化时，重新确认已有场景仍然代表当前意图，不要只保留旧 ID。

## 按需补充的场景维度

不要把矩阵机械套到所有任务；只加入会改变风险或验收判断的维度：

- **角色与权限**：匿名、普通用户、管理员、服务账号或跨租户主体，以及每个主体能做什么、不能做什么。
- **测试数据**：使用 fixture/factory 或隔离资源，记录最小数据集、唯一性、清理方式和敏感字段处理；不要硬编码环境相关 ID、token 或密码。
- **API 合同**：外部客户端依赖的请求/响应字段、错误码、兼容旧版本和 schema 变化；合同测试只能证明声明的边界，仍需保留必要的业务集成场景。
- **性能与容量**：只有存在明确性能目标时才加入；写清负载模型、测量环境、P50/P95/P99 或吞吐/错误率阈值，不能用一次本地快跑替代性能结论。
- **UI 可访问性**：仅在变更涉及 UI 时加入键盘操作、语义角色、焦点和读屏等可观察场景；自动扫描不等于完整辅助技术验收。

## 测试与验收边界

- 测试场景不是测试代码；不要一次性生成一批只验证想象行为的测试。
- 代码测试适用时，可以按场景逐个采用“先失败、再最小实现、再保留证据”的 TDD 节奏；不要把 TDD 强加给文档、配置或纯验证任务。
- bug 有便宜、稳定的测试入口时，先在未修复版本确认红测，再做最小修复并确认同一测试变绿；如果需要真实集群、生产数据或大规模基础设施，明确说明为何跳过红测，并使用最近的可执行回归检查，不为了流程新增弱测试。
- 行为发生变化时，场景契约要明确该变更应新增或更新哪些测试；纯重构则要明确由未改动的既有测试证明行为保持不变。bug 修复应有按失败模式命名的回归场景；如果无法先在未修复版本复现红测，记录原因，不把“测试编译通过”当作回归证据。
- 每个关键场景至少给出一个可单独运行的定向验证命令或运行面入口；“全套测试通过”不能证明全套测试实际覆盖了该场景。
- 关键行为和对外契约测试优先通过用户、公共 API 或稳定包边界调用被测行为，并断言字面结果、最终状态或可观察副作用；纯函数或单元测试可以调用自己拥有的最小函数边界，但仍不能只断言调用次数、非空、未抛异常、fixture 自身或实现常量。
- 断言必须能区分正确实现和已知错误实现；对汇总、计费、计数、派生状态等需要互相校验的数据，增加不变量/对账场景，而不只断言几个样例值。
- 不为不可达条件、框架内部或生成代码强行增加测试；测试由自己拥有的公共边界和可观察行为负责。
- 单元测试、集成测试、E2E 和人工验收分别标注，不把一种证据冒充另一种。单元测试可用 mock/fake 隔离外部依赖；集成测试和 E2E 应尽量使用真实依赖、真实数据路径或明确记录的测试替身。
- 优先在稳定的公共边界验证行为；不要为了提高覆盖率直接绑定内部实现。覆盖率数字只能作为辅助信号，不能替代关键场景、失败路径和最终状态证据。
- E2E 只保留少量关键用户链路、跨组件协作和真实集成；纯算法边界、API 合同细节和大量组合输入下沉到更快的测试层。每个 E2E 场景应独立、可重复、使用稳定的可观察边界和隔离数据。
- 编译通过、HTTP 200、资源创建或中间状态存在，只有在场景契约明确把它们定义为结果时才算覆盖；否则继续检查最终可观察状态。
- 异步场景使用条件轮询和明确超时，禁止用固定长 `sleep` 代替状态判断。资源创建成功后尽早登记清理；删除、回滚或恢复场景要检查终态，而不是只看请求返回码。
- 重试、增大超时或更新快照不能单独证明稳定通过；保留首失败日志、trace、截图或响应，说明重试后的结论和剩余风险。
- API 场景按适用性检查认证、授权、输入校验、错误码/错误体、幂等/冲突、超时/重试、分页排序、限流和合同兼容性；不要把不适用的矩阵项机械加入每个接口。
- 失败分析要覆盖全部失败，并按共同前置条件聚类级联失败。只有同时有近期重复运行、通过对照和明确基础设施信号时，才能把失败标为 flaky；否则保持为待确认或真实失败。
- E2E/人工场景需要记录测试环境、资源清单、清理责任和未执行影响；保留资源必须是显式选择，并在输出中报告资源 ID 和后续清理动作。
- 评审时由 `requesting-code-review` 读取场景契约并检查变更到场景的映射；本 skill 不代替代码审查。

对 retry、restart、删除、回滚、迁移和 reconciliation 场景，至少说明重复执行或中断恢复后的预期终态；不要只验证请求被接受或中间资源已经创建。

## 证据分层

在场景状态中区分以下证据，不要把较弱证据升级为较强结论：

| 证据层 | 能证明什么 | 不能单独证明什么 |
|---|---|---|
| 源码、静态检查、编译 | 结构、类型和静态约束成立 | 运行时行为、真实依赖和最终资源状态 |
| 单元测试 | 局部逻辑和隔离依赖下的行为 | 集成协议、真实数据库/网络或部署状态 |
| 集成测试 | 多组件协作和真实接口边界 | 完整用户链路或所有区域/环境能力 |
| E2E/运行面检查 | 指定环境中的完整可观察链路 | 未执行的环境、权限和场景组合 |
| 人工验收 | 用户动作和界面/操作结果 | 自动化覆盖的完整性和不可见内部状态 |

失败、跳过和阻塞都要保留证据；没有当前会话证据时，不把 `covered` 或“已通过”写成事实。

## 验证结论

需要证明一个具体修复或运行结论时，先把它写成可证伪的 claim，并记录：

- `baseline`：旧版本、失败复现或当前坏状态的同一检查；
- `treatment`：变更后的同一命令、输入、预热和环境；
- 原始证据：输出、日志、响应、截图、profile 或资源状态；
- verdict：`VERIFIED`、`NOT VERIFIED` 或 `INCONCLUSIVE`，以及仍然存在的干扰因素。

没有有效 baseline、信号受环境影响或只执行了重试时，使用 `INCONCLUSIVE`；不能把“重试后通过”单独升级为稳定覆盖。

## 输出

报告：

- 场景契约路径，或说明仅输出在回复中；
- 目标、非目标和关键假设；
- 场景表及每个 `covered`/`skipped` 的证据；
- 未覆盖场景、风险和下一步；
- 如有人工验收，给出可在几分钟内走完的步骤和每步预期结果。

## 统一约束

- 验收标准：遵循 `skills/_shared/common-acceptance.md`。
- 场景契约只描述边界和证据，不授权启动服务、写入外部系统或修改业务代码。
