Skill 的测试策略
"测试 Skill"和测试代码不同——你无法对 LLM 的输出进行精确的单元测试。但这不意味着 Skills 不可测试。关键在于找到正确的测试维度:不测试文字是否完全一致,而测试结构、逻辑和行为是否符合预期。
Skills 可测试的三个维度
维度一:结构测试(输出格式是否符合规范)
最容易自动化的测试维度。检查 Skill 的输出是否包含必要的结构元素:
✅ 可以测试的结构特征:
- 输出是否包含特定的 Markdown 标题(## 审查结果)
- 表格是否存在且有正确的列数
- 是否包含必要的关键词(✅、❌、⚠️)
- 数字是否在合理范围内
❌ 不应该测试的(不稳定):
- 具体的文字表述是否一字不差
- 建议的措辞是否和预期完全一致
维度二:行为测试(给定输入,输出是否符合预期方向)
验证 Skill 的"判断"是否正确:
输入:一个包含 SQL 注入漏洞的代码文件
预期:Skill 的输出中应该提到 SQL 注入风险(不要求措辞完全一致)
实际:检查输出是否包含 "SQL" 相关词汇
输入:一个完全没有问题的清洁代码文件
预期:Skill 的输出应该显示"通过"而不是发现问题
实际:检查输出是否包含 ✅ 且不包含 ❌
维度三:工具调用测试(工具是否被正确调用)
验证 Skill 是否按设计调用了正确的工具:
测试:运行 /review-pr --focus security
观察:Claude Code 的工具调用日志
预期:应该调用了 Grep 工具(搜索安全模式)
应该调用了 Bash 工具(运行 git diff)
不应该调用 Write 工具(只读 Skill)
手动测试框架
在没有自动化测试工具的情况下,可以建立一套结构化的手动测试流程:
测试用例设计
为每个 Skill 设计至少以下几类测试用例:
## /review-pr Skill 测试用例
### 测试 1:正常场景
- **输入**:`/review-pr --branch feature/add-login`(存在修改文件的有效分支)
- **预期**:输出包含"审查报告"标题,有表格,有总结
- **验证**:查看输出结构是否完整
### 测试 2:空内容场景
- **输入**:`/review-pr --branch main`(没有新修改的分支)
- **预期**:输出提示"未发现与 main 的差异"或类似说明
- **验证**:Skill 不应该崩溃或输出空内容
### 测试 3:参数缺失
- **输入**:`/review-pr`(不带任何参数)
- **预期**:使用当前分支,正常运行
- **验证**:输出的分支名应该是当前 git 分支
### 测试 4:无效参数
- **输入**:`/review-pr --focus invalid-value`
- **预期**:输出错误提示,说明有效的 --focus 值
- **验证**:错误提示清晰,有解决建议
### 测试 5:安全场景(--focus security)
- **准备**:创建一个包含硬编码密码的测试文件
- **输入**:`/review-pr --branch test-branch --focus security`
- **预期**:输出中应该提到该文件的安全问题
- **验证**:输出是否识别了硬编码密码风险
测试记录表
维护一个测试结果记录表(可以放在 .claude/skills/tests/ 目录):
# /review-pr Skill 测试记录
| 测试用例 | 日期 | 测试结果 | 备注 |
|---------|------|---------|------|
| 正常场景 | 2026-03-15 | ✅ 通过 | 输出格式正确 |
| 空内容场景 | 2026-03-15 | ✅ 通过 | 正确提示无差异 |
| 参数缺失 | 2026-03-15 | ✅ 通过 | 自动使用当前分支 |
| 无效参数 | 2026-03-15 | ❌ 失败 | 错误提示不够清晰 |
| 安全场景 | 2026-03-16 | ✅ 通过(修复后)| 更新了参数验证 |
## 已知问题
- /review-pr 在分支名包含 `/` 时(如 feat/auth)输出中分支名显示不完整
→ 状态:待修复
测试 Skill 的专用 Skill
可以创建一个 /test-skill Skill,专门用于运行其他 Skill 的测试用例:
---
description: 运行指定 Skill 的标准测试用例并报告结果
allowed-tools: Bash, Read
---
# Skill 测试运行器
## 目标
运行指定 Skill 的测试用例,生成测试报告。
测试用例定义在 `.claude/skills/tests/{skill-name}.test.md` 文件中。
## 参数说明(来自 $ARGUMENTS)
- **第一个参数**(必填):要测试的 Skill 名称(不带 /)
## 执行步骤
1. 解析目标 Skill 名称($ARGUMENTS 的第一个单词)
2. 使用 Read 工具读取 `.claude/skills/tests/{skill-name}.test.md`:
- 如果文件不存在,输出"该 Skill 没有测试定义文件"并停止
3. 读取 Skill 文件本身(`.claude/skills/{skill-name}.md`),了解其设计意图
4. 基于测试文件中定义的测试用例,逐个分析:
- 测试的输入场景
- 期望的输出行为
- 当前 Skill 的设计是否覆盖了这个场景
5. 生成测试覆盖报告
## 输出格式
Skill 测试分析:/{skill-name}
测试用例总数:N 设计已覆盖:N 个 存在设计缺口:N 个
设计缺口分析
| 测试用例 | 问题 | 建议的修复 |
|---|---|---|
| [用例名] | [Skill 未处理的场景] | [修改建议] |
建议
[总体改进建议]
本节记录清单
- [ ] 为你最重要的 Skill 设计至少 5 个测试用例(正常/边界/错误场景)
- [ ] 创建
.claude/skills/tests/目录,存放测试用例文档 - [ ] 建立测试结果记录表,跟踪每次测试的结果
- [ ] 在 Skill 更新后运行测试用例,确认没有回归
下一节:调试 Skill:定位失败的系统化方法——测试发现了问题,怎么找到根本原因并修复?