hwy-game

vetta-testing

为 OpenVetta 的功能变更、Bug 修复、重构、公共合同和 UI 交互设计、编写或审查测试;在决定测试范围、补充回归测试、覆盖用户常见使用流程或评估测试质量时使用。纯文档或没有运行时行为变化的编辑不使用。

hwy-game 0 Updated 1mo ago
GitHub

Install

npx skillscat add hwy-game/metoai/vetta-testing

Install via the SkillsCat registry.

SKILL.md

OpenVetta 测试设计与编写

目标

编写能在真实回归发生时可靠失败、能说明哪项用户行为或稳定合同被破坏、且维护成本与风险相称的测试。不要以覆盖代码行、内部调用次数或大量快照代替行为证据。

开始前完整阅读目标目录适用的最近一级 AGENTS.md、相关包 README、现有测试和实现。测试命令与门禁以仓库根 AGENTS.md 和 docs/dev/quality-gates.md 为准;更近一级规则可以收紧本 Skill。

先定义要证明的行为

编码前列出:

  1. 本次会改变的用户可见行为或公共合同。
  2. 必须保持的不变量、兼容路径、事件顺序和副作用。
  3. 用户在受影响功能中最可能执行的常见使用操作路径或流程。
  4. 风险最高的边界、失败、取消、重试、恢复或持久化场景。

把每个场景写成 Given / When / Then:

  • Given:用户已有的状态、合理默认配置和必要前置条件。
  • When:用户从正常入口执行的连续操作,而不是直接调用本应隐藏的内部函数。
  • Then:用户可见结果、公开输出、持久化事实、外部副作用或明确错误。

只覆盖本次改动实际影响的连续步骤,不机械穷举全产品路径。若多个常用入口经过不同的状态、协议或持久化边界,且改动同时影响这些边界,应分别覆盖代表性流程。

按任务选择测试组合

  • Bug 修复:先建立能在旧实现失败的最小复现或明确基线,再写回归测试;修复后还要运行受影响的常见用户流程测试。
  • 新功能或行为变化:至少覆盖一条代表性常见用户流程,再为新增分支、关键边界及可恢复失败添加定向测试。
  • 内部重构:明确保持的不变量,使用已有测试、差分测试或合同测试证明外部行为、事件顺序和副作用未变。
  • 公共合同变更:检查生产者、消费者及兼容路径,覆盖 Schema、协议、序列化、错误和版本边界。
  • UI 交互变化:覆盖真实渲染、事件接线、用户输入、提交、焦点、可访问语义、加载和错误恢复;纯函数测试不能替代组件测试。
  • 权限、并发、取消、重试和生命周期:覆盖允许与拒绝、竞争顺序、清理、重复执行和恢复等会造成高后果的状态转换。

纯文档、无逻辑文案、类型转发或已由现有合同准确覆盖的机械改动可以不新增测试,但仍需运行适当验证并在交付中说明依据。

识别用户常见使用流程

“常见”指普通用户通过产品正常入口、在合理默认配置下完成目标,而不是测试专用入口、调试开关或罕见内部调用。根据功能实际支持的能力和本次改动选择流程,例如:

  • 会话与 Agent:新建或恢复会话 → 输入任务或添加上下文 → 发送 → 查看流式回复或工具结果 → 继续追问、取消或重试 → 重新打开后看到正确历史。
  • 工具与权限:触发需授权的操作 → 查看权限说明 → 批准或拒绝 → 操作继续或被阻止 → 收到明确结果和错误反馈。
  • Plugin、Skill 与 MCP:安装或导入 → 校验清单与确认权限 → 启用 → 在会话中调用 → 禁用、更新或卸载后状态正确。
  • 设置、Provider 与运行时:打开设置 → 修改并校验配置 → 保存 → 当前会话或重启后生效 → 配置无效或资源不可用时得到可恢复反馈。
  • Agent Team:选择或创建团队 → 发起任务 → 成员执行并展示进度 → 汇总结果 → 继续协作、结束或恢复团队会话。
  • 文件与项目:打开项目或选择文件 → 执行读取、编辑或生成操作 → 查看变更与状态 → 确认、重试或重新打开后结果一致。

这些是选路示例,不是要求每次修改都覆盖全部流程。优先从产品入口、用户文档、现有组件接线和生产调用链确认真实流程,不根据测试便利性发明产品行为。

选择最低但充分的测试层级

  • 单元测试:纯计算、解析、选择、校验和状态转换。
  • 组件测试:UI 渲染、输入、提交、焦点、可访问语义和异步反馈。
  • 合同测试:公共 API、IPC/RPC、Tool/Prompt Schema、事件、序列化和跨包边界。
  • 集成测试:跨模块流程、真实内部装配、持久化以及多个状态转换。
  • E2E:只有真实浏览器、Electron、进程、文件系统、打包布局或网络边界无法由低层测试证明时使用。

用户流程测试从用户可触达入口或最接近该入口的组件、服务公共接口进入,尽量使用真实内部装配。能够由组件、合同或集成测试证明时,不要机械升级为 E2E。只有用户在当前任务中明确要求时才运行 verify:ui:*。

写出稳定且有诊断力的测试

  • 测试名称描述用户行为或稳定合同及预期结果,例如“用户拒绝工具授权后不执行操作并看到已取消状态”。
  • 使用 Arrange / Act / Assert 或 Given / When / Then,使前置状态、动作和结果清晰分离。
  • 断言用户可见结果、公开返回值、持久化事实和必要副作用;不要锁定私有字段、脆弱 DOM 层级或偶然调用次数。
  • 一个测试表达一个清晰场景,但允许验证同一用户流程中的连续状态,不要把流程拆成只能按顺序运行的多个测试。
  • 对纯逻辑的多组边界输入优先使用表驱动测试;对用户流程保留可读的独立场景。
  • 时间、随机数、并发和重试使用可控时钟、固定输入或显式同步点;不要用任意 sleep 等待。
  • 每个测试独立建立和清理状态,释放计时器、订阅、进程、临时文件和数据库连接,不依赖执行顺序。
  • 快照只用于稳定且整体形状本身就是合同的输出;不要用大面积快照掩盖关键断言。

Mock 与测试替身

只在真实外部边界使用 Mock,例如 Provider、网络、操作系统、外部进程或不可控时间。内部协作者优先使用真实实现、内存存储或行为明确的 Fake。

不要把被测模块内部全部 Mock 后只验证调用:

expect(sendMessage).toHaveBeenCalledOnce();

应优先证明用户目标或稳定事实成立:

expect(screen.getByText("分析完成")).toBeVisible();
expect(await conversationStore.load(sessionId)).toContainEqual(
	expect.objectContaining({ text: "分析完成" }),
);

只有当“调用某个外部边界”本身就是公开合同或必要副作用时,才断言其参数和次数。

审查测试质量

审查新增或现有测试时逐项判断:

  1. 若实现出现目标回归,这个测试是否真的会失败?
  2. 是否覆盖了本次改动影响的代表性用户常见操作流程,而不只是孤立函数或异常分支?
  3. 断言是否面向可观察行为和稳定合同?
  4. Mock 是否只位于真实外部边界,是否意外绕过了关键生产接线?
  5. 异步、时间、并发和资源清理是否确定且无任意等待?
  6. 测试层级是否足够,又没有不必要地升级为缓慢 E2E?
  7. 失败信息能否直接指出被破坏的行为?

发现缺口时,优先补能捕获真实回归的最低层测试,不重复相同断言,也不为了覆盖率数字制造低价值用例。

运行与交付

使用仓库统一入口,不使用裸 bun test、bunx vitest、npx vitest 或直接 vitest:

bun scripts/quality/run-vitest.mjs --run <test-file>
bun run test:pkg <name>
bun run test:changed
bun run check:quick
bun run check

选择与改动相称的最小充分范围:先跑定向测试,一轮编辑后跑 check:quick,涉及多个包或范围不明确时跑 test:changed,代码任务完成后跑一次 check。check 不运行测试,不能替代行为测试。

交付时说明覆盖了哪些用户流程或合同、实际运行了哪些测试与检查、哪些未运行及原因、剩余风险和兼容性影响。不得声称未执行的验证已经通过。

Skill 维护

.agents/skills/vetta-testing/SKILL.md 是事实源。修改本 Skill 时同步更新 .claude/skills/vetta-testing/SKILL.md,并验证两份文件内容一致。

Categories