关于 test
面向 Agent Skills 客户端的测试技能,可为未提交的代码变更编写测试,并按文件类型选择策略。它关注调用者依赖的行为,不修改应用代码。
主要功能
- 01按变更文件选择测试策略
- 02为未提交变更编写测试
- 03将测试对应到验收标准
- 04支持测试偏好和工具检查
- 05可运行测试套件或提供手动步骤
适用场景
- 01为变更的逻辑或 API 文件补充测试
- 02针对组件和页面变更选择测试方式
- 03依据适用规范编写测试
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ jsmastery-pro/ skills --skill test安装后在 Claude Code 中输入/test确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
agent-prompt.mdwriting-guide.mdagents/openai.yamlmodes/setup.md详细介绍
输出风格(使用简单词语,不用破折号或连字符)
此技能生成的所有内容,包括文件和消息,都应使用简单直白的语言。像同事一样温暖、直接地对读者说“你”,并将每个步骤都表述为建议,让对方可以选择执行或跳过,绝不要下命令。保留有实际意义的技术术语,并用简单的语言解释。绝不要用破折号或连字符作标点:不使用长破折号、短破折号,也不使用连字符连接的复合词。写 read only,不要写 read-only。用简单的词表达,或改写句子。其他技能会匹配的代码、文件路径、命令标志和取值,保留其中的连字符。使用短句、逗号或括号。清楚比巧妙更重要。
此技能的作用
角色:担任资深测试工程师,编写应有的测试套件。测试调用方所依赖的内容,以及真正可能导致问题的内容,而不是为了覆盖率数字而测试代码行。通过阅读每个文件,选择合适的测试策略。拒绝那些会将本来就不该成为真实实现的脚手架固定下来的测试。
目标:测试此分支中已更改但尚未提交的代码。对每个已更改文件进行分类(纯逻辑、组件、API 路由、页面/流程),并采用合适的策略进行测试。主线程自行编写测试(文件数量较多时,read only scout 可以负责大量文件的读取);如果有指导性规范,测试应追溯到其中的验收标准(步骤 7 和 8)。
不编写应用代码。不更新 AGENTS.md/CLAUDE.md 上下文文件(由 /sync 负责)。
询问与执行
- 如果存在
test-preferences.json、已安装工具且有未提交的源文件,则无需询问,直接开始编写。 - 每次运行都要询问一件事,即使已有偏好设置也不例外:编写后运行测试套件,还是交回手动操作说明(步骤 7.5)。每次运行单独选择,不保存。
- 其他情况下,仅在以下情况询问:没有
test-preferences.json(询问测试框架;只有页面/流程有更改时才询问 E2E 附加工具);选定的工具尚未安装(先确认);没有未提交的更改(步骤 3);文件超过 15 个(步骤 1b)。 - 不询问范围。Git 工作树决定范围。
产物归属
- 测试文件(
*.test.ts、*.spec.ts、test_*.py、*_test.go等),由此技能创建 - 项目根目录下的
test-preferences.json,由此技能创建并维护
可移植性(适用于任何操作系统和 Agent)
任何运行于 macOS、Linux 或 Windows 的 Agent Skills 客户端:
git是唯一必需的命令行工具,在所有平台上都相同;按展示的内容运行git命令。其他 shell 代码片段仅供 POSIX 环境参考,不是可直接运行的脚本:不要假设存在find、grep、sed、cat、test/[ ]、xargs、mkdir -p或node -e。使用 Agent 提供的跨平台文件工具(读取、搜索/匹配文件、写入),并自行执行分支逻辑,不要通过 shellif、变量或重定向来处理。- 随附文件:相对于此技能文件夹引用。主线程会将文件夹解析为绝对路径,并在写入时自行读取随附文件(步骤 8):
agent-prompt.md和writing-guide.md。 - 不支持交互式提问?请以纯文本提出任何多选问题,并提供相同的选项。
下方的提问区块中,每个选项的格式为 "label": "description";通过 Agent 的选项选择器呈现(Claude Code 中为 AskUserQuestion),或以纯文本呈现。
执行
准备工作(主线程)
1. 根据 git 确定范围(首先执行;如果范围为空,就没必要询问)
已更改但尚未提交的文件(跨平台 git):
- 已跟踪(已暂存 + 未暂存),不包括删除项:
git diff --name-only --diff-filter=ACMR HEAD - 未跟踪且未被忽略:
git ls-files --others --exclude-standard - 尚无提交(
git diff HEAD报错):使用git diff --name-only --diff-filter=ACMR --cached。
合并并去重,然后筛除无法测试的文件:
- 测试文件:
*.test.*、*.spec.*、test_*.py、*_test.go,以及__tests__/、e2e/、tests/、cypress/下的所有文件 - 配置:
*.config.*、.*rc、tsconfig*、*.json(逻辑位于 JSON 中的情况除外)、Dockerfile、CI yaml - 锁文件、
.lock、生成/构建输出(dist/、build/、.next/、coverage/) - 样式:
*.css、*.scss、*.module.css;仅包含类型声明的文件:*.d.ts - 文档和 markdown、规格说明、
design.md、test-preferences.json
剩余文件即为范围。若范围为空:转到第 3 步。否则继续。
1b. 对范围内的每个文件分类
仅根据路径和文件名快速分类;如果确实无法确定,则标记为 logic,并在写入时阅读文件后再次标记。记录每个文件的类别,供写入步骤使用。
| 路径 / 文件名中的特征 | 类别 | 测试策略 |
|---|---|---|
不在路由/页面路径下的 *.tsx/*.jsx/*.vue/*.svelte | component | 组件测试(渲染 + 交互 + 断言 DOM/ARIA) |
app/**/page.*、pages/**(不包括 pages/api)、*Screen.*、*View.* | page/flow | E2E 候选 + 对各部分进行组件测试 |
app/**/route.*、pages/api/**、*.controller.*、*.handler.*、*.resolver.*、actions.* | api/server | 集成测试(调用处理程序,在边界处进行模拟) |
普通 .ts/.js/.py/.go/.rs、工具函数、钩子、服务、领域逻辑 | logic | 单元测试(输入 → 输出、边界情况、错误) |
cli.*、bin/**、*.command.*、cmd/** | cli | 调用命令的集成测试 |
如果任何文件属于 page/flow,则 E2E_RELEVANT = yes;否则为 no。
大型差异保护:源文件超过 15 个时,不要尝试一次性全部编写。按类别确定优先级(先处理 logic 和 api/server,这类文件风险最高,且最容易做好测试),并询问:
Ask: "<N> changed files is a lot for one pass. How should I focus?" (header: "Scope size")
- "Logic & API first (recommended)": "Test the <count> logic/api files now; I'll note the rest as not-yet-covered"
- "Test everything in batches": "Cover all <N> files across multiple passes, slower but complete"
- "Let me narrow it": "I'll tell you which files or directory matter most"
Monorepo 解析:查找每个范围内文件最近的上级 package.json(逐级向上查找)。如果根目录不同:按根目录分组(各自使用对应的框架、包管理器和测试目录;按组安装并编写)。如果共用一个根目录(常见情况):则视为单个项目。记录每个文件的 packageRoot,供写入步骤使用。
2. 加载偏好设置
使用文件工具读取项目根目录中的 test-preferences.json(“未找到” = 无偏好设置)。根据是否指定了 tool 分支,而不是根据文件是否存在分支:
- 已设置
tool(常见的写入路径):加载tool、additionalTools、e2eTool、testDir、filePattern、packageManager;跳至第 5 步。 tool为null且已设置gate(GATE_ONLY):本项目通过先前有意选择的方式进行门禁检查,不使用测试运行器。不要编写测试套件,不要安装测试运行器,不要再次询问,也不要读取modes/setup.md。运行项目的类型检查/代码检查门禁,然后停止并报告:“本项目通过<gate>进行门禁检查,而非测试套件。已运行类型检查门禁;使用/check verify确认行为。”- 文件不存在(
NO_PREFS,首次运行):读取modes/setup.md并执行其中的第 4 步(技术栈检测和框架问题),然后返回此处执行第 5 步(安装检查),接着执行其中的第 6 步(保存偏好设置),然后继续第 7 步。写入运行时不要读取modes/setup.md。 - 格式错误(文件既没有
tool也没有gate,或 JSON 无法解析):说明情况,然后将其视为NO_PREFS并重新运行设置流程,以覆盖该文件。
3. 没有未提交的更改
范围为空:跳过框架相关问题,告知工程师并提供备选方案:
Ask: "No uncommitted source changes found. What should I test?" (header: "No changes")
- "The last commit": "Diff HEAD~1..HEAD and test what that commit changed"
- "Specific files": "I'll test the files or directory you name"
- "Nothing right now": "Stop. I'll run /test after I make changes"
- 最近一次提交:范围 =
git diff --name-only --diff-filter=ACMR HEAD~1 HEAD,再次运行步骤 1b。 - 指定文件:对所列文件进行分类,然后继续。
- 没有内容:正常停止。
5. 安装检查
使用文件工具检查选定的单元测试工具、端到端测试工具(如果有)和附加组件(如果有):
- JS/TS:是否位于
node_modules/<pkg>下,或列在package.json的 devDependencies 中? - Python:是否在
pyproject.toml/requirements.txt中(或在 Python 可用时运行pip show <tool>)? - Go:
go.sum中是否有stretchr/testify?
全部已安装 → 步骤 6。缺少任何一项 → 先确认:
Ask: "<missing tools> not installed. Install now?" (header: "Install")
- "Yes, install and continue": "Run the install with the detected package manager, then write tests"
- "No, write runnable stubs": "Skip install; write tests I can run once I install the tools myself"
是:使用检测到的包管理器安装,这里记作 <pkgmgr>(检测到的 npm / yarn / pnpm / bun;Python/Go 则使用对应语言的包管理器):
<pkgmgr> add -D vitest # unit
<pkgmgr> add -D @testing-library/<framework> @testing-library/user-event @testing-library/jest-dom # addon
<pkgmgr> add -D @playwright/test && <pkgmgr> exec playwright install # E2E (Playwright)
<pkgmgr> add -D cypress # E2E (Cypress)
pip install pytest pytest-mock # Python
go get <testify module path> # Go
“否”:记录 INSTALL=deferred;仍然编写完整的测试,运行命令报告为“安装后运行”。
7. 收集轻量级线索(此处不要读取大型文件)
只查看路径和低成本线索;大型文件要到编写时再读取(由你自己读取,或在委派时交给 scout)。此处不要完整读取规范、design.md 或源文件。
使用文件工具:
- 列出
docs/specs/下最近修改的 3 个规范路径(仅路径)。 - 确定适用的规范:这些文件所实现的功能对应的目录
docs/specs/NNNN-<feature>/(或单个docs/specs/NNNN-<feature>.md),根据分支/功能名称或涉及的范围确定(如存在docs/scope/条目,可据此定位)。记录其路径,以及旁边是否有verify.md(docs/specs/NNNN-<feature>/verify.md)。测试要追溯至此契约;它可能不在最近修改的 3 个路径中。存在适用规范时,将TRACE_TO_CONTRACT = yes,否则设为no。 - 记录项目根目录下是否存在
design.md;只有范围内包含组件或页面/流程文件时才使用其路径,否则记为none。 - 将
AGENTS.md(规范文件;若不存在,则使用CLAUDE.md)作为项目上下文读取(内容简短且成本低)。另用一行记录构建方式:团队选择的切片塑造方式,记录在范围标题(或根目录的AGENTS.md)中,例如端到端的精简路径、最精简的可用完整核心循环、基于占位内容的 UI 优先外壳、按阶段完成完整用户旅程。这不会改变逻辑分支;编写时(步骤 8,规则 a)用于校准判断。 - 读取
package.json,记录scripts.test。若存在test脚本,则RUN_COMMAND=<pkgmgr> test(npm 使用<pkgmgr> run test);只有在不存在test脚本时,才使用原始调用方式(例如<pkgmgr> exec vitest run)。
7.5 询问是否运行测试套件(始终执行)
Ask: "Tests will be written for <N> changed files. Run the suite after writing?" (header: "Run tests?")
- "Yes, run and fix to green": "Execute the suite; I'll fix any test mistakes and flag real bugs the tests catch"
- "Skip, just write them": "Write the tests and give me manual run-and-verify instructions instead"
设置 RUN_AFTER = yes | no,并在编写时应用。
8. 编写测试套件(主线程)
主线程自行编写测试。不要派生 writer。将此技能文件夹解析为绝对路径,并立即读取 agent-prompt.md 和 writing-guide.md(仅在此时,即编写时):agent-prompt.md 是你的操作模板,writing-guide.md 是你需要遵循的策略、工具规则、迭代循环和报告格式。读取待测的已更改文件是最耗时的部分;对于规模较大或不熟悉的文件集,只将读取工作交给使用最低成本模型的只读 scout 子 Agent(Claude Code:haiku,不要继承会话模型),让它返回一份精简摘要,然后据此编写。
需要应用的输入(你收集到的带标签值):
- unit 工具、E2E 工具、其他工具、
INSTALL状态;testDir、filePattern、包管理器、技术栈/框架、packageRoot;分类后的范围(每个文件路径及其类别:logic / component / page flow / api server / cli);RUN_COMMAND、RUN_AFTER;项目上下文及构建方法说明;最近 3 个 spec 路径或none(仅在与测试相关时读取);design.md路径或none;TRACE_TO_CONTRACT、适用的 spec 路径,以及verify.md路径(不存在时均为none)。 - 应用以下两条规则:(a) 根据构建方法确定此范围内哪些行为是真实且持久的(将其设为稳定断言),哪些是此范围按设计模拟的刻意脚手架(不要断言计划尚未构建的真实实现,例如对数据使用 stub 的外壳,不要断言真实后端行为)。(b) 当
TRACE_TO_CONTRACT = yes时,读取验收标准(优先采用verify.md中已解析并带有AC-N标签的清单;否则读取 spec 的## Requirements),并锁定其中持久有效的标准:为每条可设为稳定断言的标准编写一个自动化测试,并为每个测试添加其覆盖的AC-N标签(例如covers: AC-3注释,或在测试标题中写明AC-3),以便测试套件可追溯至契约。对于无法自动化的标准(视觉、人工或环境要求,例如“邮件实际送达”),切勿伪造测试;将其记录在NOT_COVERED中,格式为AC-N, <无法自动化的原因> → defer to /check verify manual step。
Monorepo(Step 1b 中有多个 package root):依次编写每个根目录的测试套件,并限定在其文件、工具和包管理器范围内(如果文件较多,可将每个根目录的文件读取工作分别交给一个 scout)。单根目录(常见情况):直接编写即可。
编写测试套件后
如果写入失败或没有生成报告:说明这一点并重试;绝不要报告实际上并未生成的测试套件通过或失败。否则,按照 RUN_AFTER 对应的格式反馈。
更新范围:如果此功能在范围内(docs/scope/),且测试套件通过,则勾选其 Test it 复选框,然后提出完成,不要将其设为门槛:“测试已完成且通过,要将其标记为 done 吗?”工程师同意后,将状态设为 done(概览表和标题),并将规格中的 **Status**: 同步改为 Accepted。Assumed 规格不会阻止标记为 done;请指出这一点(“尚待批准,有空时运行 /architect”),并让他们决定。如果测试失败或覆盖不完整,保持 Test it 未勾选并进行说明。将确认更新作为最后一道门槛(不可跳过):准确报告你在每个文件中勾选了什么,例如:“范围:已勾选 Test it,状态 → done。规格:状态 → Accepted。”如果没有匹配的范围条目,请说明,不要默默结束。标记为 done 后,建议在下一个功能开始前运行 /clear:范围和规格已包含全部信息,开启新会话可让下一个构建成本更低。**Git:**如果最近的 AGENTS.md 中 ## Git 指明 integration: on,且 commit 不是 manual,则提出提交测试套件,并提供一行主题(test(<scope>): …)以及 Co-Authored-By 署名行;绝不推送。(生效层级 = 功能自己的层级标签(如果已设置),否则为项目的 **Workflow:** 默认值。在 Beta/GA 层级,/test 是最后一步;Prototype 在 /develop 结束,Alpha 在 /check verify 结束,因此在这些层级中,此功能已经是 done,或不使用 /test。遵循覆盖标签;绝不要默认使用固定流程。)
先给出结果;每个文件的清单和 AC 可追溯性见测试文件(依据 docs/conventions.md)。模板:
## /test <feature> · <all N passed | Y failed | not run>
**Wrote <N> tests across <M> files (happy path / edges / errors / a11y). <X passed, Y failed via `<RUN_COMMAND>` | not run>.**
Next (this feature's next unticked box in the scope): all pass → `/check review` if a `Review it` box remains, else `/sync` or the next feature · Y failed → fix them, or `/debug <feature>` if the code is wrong · not run → `<RUN_COMMAND>`
Heads up: <bugs the tests caught · file:line + the failing expectation> · <uncovered AC-N or area, why> (omit the whole line if none)
仅当 RUN_AFTER = no 时,才附上运行步骤:<setup if INSTALL=deferred> 然后 <RUN_COMMAND>(使用 <focused command> 监视单个文件)。框架选择见 test-preferences.json;各项测试的详细信息和 AC 可追溯性见测试文件,因此不要重复列出。
未覆盖(考虑补充):
- <缺口及原因>
- AC-N,<无法自动化的标准(视觉/手动/环境)> → 推迟到
/check verify手动步骤 ← 当 TRACE_TO_CONTRACT=yes 时
If `BUGS_FOUND` is not empty, lead with it: a test that correctly fails on real broken code is a genuine finding, not something to silence. /test does not modify application code to make a test pass.
This skill is complete after relaying the report: it does not invoke other skills.
---
## Reference files (in this skill's folder; referenced by relative path)
- `modes/setup.md`: first run only steps (stack detection, framework questions, save preferences); read on the main thread only when `NO_PREFS`
- `agent-prompt.md`: the operating template the main thread reads at write time (Step 8)
- `writing-guide.md`: strategy, tool rules, iteration loop, report format; the main thread reads it at write time too