关于 test-coverage
test-coverage 是用于扩展单元测试覆盖率的技能,面向需要补充未覆盖分支、错误路径和边界条件的开发者。它先测量覆盖率基线,再编写并验证测试,并通过分支和暂存约束保护仓库改动。
主要功能
- 01检测项目语言与测试框架
- 02测量覆盖率基线
- 03定位分支与边界测试缺口
- 04编写并自检单元测试
- 05验证覆盖率提升与测试稳定性
适用场景
- 01响应 CI 覆盖率偏低
- 02补充错误路径测试
- 03为发布前测试套件查漏
- 04处理代码审查发现的测试缺口
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ luongnv89/ skills --skill test-coverage安装后在 Claude Code 中输入/test-coverage确认已加载。
附带文件docs/README.mdreferences/unit-test-quality.md
详细介绍
测试覆盖率扩展器
针对未测试的分支和边界情况,扩展单元测试覆盖率。
适用场景
- 用户要求“提高测试覆盖率”“添加更多测试”“扩展单元测试”或“覆盖边界情况”
- CI 流水线报告覆盖率偏低,用户希望提高覆盖率
- 代码审查指出未测试的错误路径或边界条件
- 用户希望在发布前找出并填补现有测试套件中的缺口
技术栈(工作流第 1 步之前检测)
根据项目的清单文件检测项目语言,并在下方工作流中使用相应命令:
| 清单文件 | 技术栈 | 覆盖率命令 | 测试框架 |
|---|---|---|---|
package.json | JavaScript/TypeScript | npx jest --coverage 或 npx vitest --coverage | Jest、Vitest、Mocha |
pyproject.toml | Python | pytest --cov=. --cov-report=term-missing | pytest、unittest |
go.mod | Go | go test -coverprofile=coverage.out ./... | testing、testify |
Cargo.toml | Rust | cargo tarpaulin 或 cargo llvm-cov | 内置测试框架 |
如果找不到这些清单文件,请参阅边缘情况——“未检测到测试框架”。
编辑前同步仓库(必需)
在现有仓库中创建、更新或删除文件之前,先将当前分支与远程同步。首先保存 git status --porcelain 的结果作为同步前列表;第 4 步绝不会暂存这些路径。
branch="$(git rev-parse --abbrev-ref HEAD)"
git fetch origin
git pull --rebase origin "$branch"
如果工作区不干净,先暂存更改,再进行同步,然后恢复更改:
git stash push -u -m "pre-sync"
branch="$(git rev-parse --abbrev-ref HEAD)"
git fetch origin && git pull --rebase origin "$branch"
git stash pop
如果缺少 origin、无法拉取,或发生变基/暂存冲突,请停止并在继续之前询问用户。
工作流
0. 创建功能分支
进行任何更改之前:
- 运行
git rev-parse --abbrev-ref HEAD。如果输出的是一个为此任务创建、且不是main或master的分支,请跳到第 1 步。 - 运行
git branch -a,记录现有分支通常使用的前缀(例如feat/、feature/、test/)。 - 使用该前缀创建并切换到新分支。如果没有常用前缀,则将分支命名为
feat/test-coverage。
1. 分析覆盖率
运行上方检测到的技术栈对应的覆盖率命令。记录总覆盖率以及通过/失败数量,作为基线。如果有任何测试失败,请在此处停止(参阅边缘情况)。
根据报告找出:
- 未测试的分支和代码路径
- 覆盖率偏低的文件/函数(优先处理低于 60% 的文件)
- 缺失的错误处理测试
2. 找出测试缺口
检查覆盖率偏低的代码,查找:
- 逻辑分支(if/else、switch)、状态转换和副作用
- 错误路径和无效输入,实际缺陷往往出现在这些地方
- 边界值:空、null、零、最小值、最大值和差一错误
- 尚无测试覆盖的正常路径
3. 编写测试
- 阅读
references/unit-test-quality.md。 - 使用检测到的技术栈所对应的测试框架,为第 2 步发现的缺口编写测试,并遵循该文件的规则:结果确定、隔离、快速、每个测试只验证一种行为,并断言行为而非实现。
- 根据文件中的四个自查问题逐一检查每个新测试。重写未通过任一问题的测试。
4. 验证改进
- 运行完整测试套件。如果之前通过的测试现在失败,请报告
PARTIAL并指出测试名称。如果新测试失败,请单独再运行两次。如果单独运行时有一次通过,则该测试不稳定:按第 2 项处理。只有在三次运行都失败时,才阅读失败信息并判断哪一方有问题:- 测试有问题(设置不当,或断言了代码从未承诺的行为):修复测试,然后重新运行。
- 代码有问题(测试检查的行为符合代码的 docstring、类型或名称所承诺的行为):这是疑似 bug。删除该测试,以及仅供该测试使用的任何导入或 fixture,然后重新运行第 1 项。不要更改生产代码,也不要放宽断言来迁就代码。在
Decision:下报告该 bug,并附上测试代码和失败输出。运行结果仍可为COMPLETE;在Result:行指出该 bug。该测试将成为修复此 bug 的回归测试。 - 无法判断哪一方有问题:按疑似 bug 处理。
- 单独运行新测试两次(例如
pytest tests/test_parser.py、go test ./internal/store -count=1 -run '^TestKey'、cargo test key_)。如果新测试在任意一次运行中失败,说明它受测试顺序、共享状态或时序影响。根据references/unit-test-quality.md中的不稳定性表修复一次,然后重复第 1 项和第 2 项。如果仍然失败,则删除该测试,并在Uncertainty:下列出。 - 运行与第 1 步相同的覆盖率命令。
- 将新的总覆盖率与第 1 步的基线比较。如果没有严格提高,请报告
PARTIAL,并列出第 2 步中仍未覆盖的部分。 - 如果第 1 项中的完整测试套件通过,且第 2 项中的新测试文件通过,请在功能分支上提交新测试,并在提交信息中记录覆盖率前后百分比以及新覆盖的文件。使用明确路径逐个暂存本次编写的测试文件(
git add tests/test_parser.py);绝不要使用git add -A、git add .或git commit -a,以免把 Repo Sync 恢复的用户工作一并提交。绝不要暂存预同步列表中的路径。只有在提交信息中说明原因时,才暂存变更过的 manifest 或 lockfile(未安装覆盖率工具)。提交前检查git diff --cached --name-only。在Uncertainty:下列出每个未暂存的变更文件;如果跳过提交(测试套件失败或存在回归),则列出所有新测试文件。 - 输出最终报告。报告以
Result:开头,后接COMPLETE、PARTIAL — 原因或BLOCKED — 原因,并包含:Evidence:运行过的命令、前后总数、通过/失败数量,以及第 2 项的重跑结果Uncertainty:未检查的内容(例如,排除的路径、未运行 CI、未验证输出的已覆盖代码行)Decision:需要审批的操作,或No approval needed,然后列出仍需用户执行的操作(例如推送分支、创建 PR)- 新测试用例数量,以及覆盖率提升最大的文件
预期输出
在 Python 项目上成功运行后,最终验证报告如下所示:
Result: COMPLETE — coverage 61% → 84%, all tests pass
Evidence: pytest --cov=. --cov-report=term-missing (before): 61% (47/77 statements), 47 passed
same command (after): 84% (65/77 statements), 56 passed, 0 failed
9 new tests run on their own, twice: 9 passed both runs
Uncertainty: CI not run; src/vendor/ excluded from coverage
Decision: No approval needed. Next: push feat/test-coverage and open a PR.
New tests added: 9
Files improved:
- src/parser.py 52% → 91% (+7 tests: null input, empty string, unicode overflow)
- src/auth.py 71% → 88% (+2 tests: expired token, missing header)
验收标准
当且仅当以下所有条件都满足时,运行才算通过:
- 存在针对检测到的技术栈、可运行的命令生成的覆盖率报告(例如,
jest --coverage、pytest --cov、go test -cover)。 - 运行后的总覆盖率严格高于运行前的基线——不得添加无法提升该指标的测试。基线为 100% 时是唯一例外(见“边界情况”)。
- 新测试针对此前未测试的分支、错误路径或边界值,而非重复已有断言。
- 每个新测试都对返回值、抛出的错误或可观察到的效果进行断言。仅执行代码的测试不计入。
- 新测试不得使用网络、系统时钟、未设种子的随机数或
sleep(),也不得使用真实数据库;现有单元测试已使用的测试数据库 fixture 除外。 - 提交前,本地完整测试套件通过(
npm test、pytest、go test ./...等),且新测试单独运行两次均通过。 - 暴露疑似 Bug 的新测试不得纳入提交,并须在
Decision:下报告。不得放宽断言以迎合代码。 - 所有新测试都位于功能分支上(例如
feat/test-coverage),绝不得位于main/master上。 - 提交消息须记录前后覆盖率百分比,以及新增覆盖的文件。
- 提交中只能包含本次运行写入的文件,且必须通过明确指定路径来暂存。
如果任何一项未通过,最终报告须标明 PARTIAL 或 BLOCKED,并说明原因。
最终报告还必须易于理解:
- 第一行须给出
COMPLETE、PARTIAL或BLOCKED,并说明原因。 Evidence:(运行的命令及观察到的总覆盖率)须与Uncertainty:(假设及未经检查的行为)分开。- 每个覆盖率数字都须能追溯到命令输出:包括前后总覆盖率及各文件的覆盖率百分比。
Decision:须指出需要获得的批准,或写明No approval needed,并指出任何仍需用户采取的操作。
这些是指令检查。若没有审核者反馈,报告是否易于人理解仍无法确认;Agent 检查也无法确认这一点。
边界情况
- 未检测到测试框架:Skill 会检查
package.json、pyproject.toml、Cargo.toml或go.mod中是否存在测试依赖;如果没有找到,则会在编写任何测试前询问用户要使用哪个框架。 - 未安装覆盖率工具:如果覆盖率命令因缺少工具而失败,则将其作为开发依赖安装(
pytest-cov、nyc、cargo tarpaulin等),并重新运行该命令一次。如果再次失败,则停止并附上错误输出,报告BLOCKED。 - 现有测试已失败:如果步骤 1 的基线运行报告测试失败,则不要编写新测试。停止并列出失败测试的名称,报告
BLOCKED。 - 覆盖率已达到 100%:如果步骤 1 的基线为 100%,则不要添加测试。以基线作为证据,报告
COMPLETE并停止。 - 覆盖率报告中包含生成代码或供应商文件:将自动生成文件和第三方路径(例如
node_modules/、vendor/、dist/、build/,以及带有生成代码标头的文件)排除在步骤 2 的缺口列表之外,并在Uncertainty:下列出。 - 异步/并发代码路径:使用框架提供的异步测试工具(例如
pytest-asyncio或 Jest 假计时器)。绝不得使用裸同步包装器,也不得使用sleep()等待异步工作完成。 - 代码直接读取时钟、随机数或全局状态:使用测试框架自带的工具进行替换:pytest 的
monkeypatch(针对被测模块导入的名称)、jest.spyOn或vi.spyOn,或者 Jest 或 Vitest 的假计时器。如果这些工具都无法触及相关代码,则不要重构生产代码来增加接缝。该缺口应保持未测试状态,并在Uncertainty:下列出。
步骤完成报告
完成每个主要步骤后,按以下格式输出状态报告:
◆ [Step Name] ([step N of M] — [context])
··································································
[Check 1]: √ pass
[Check 2]: √ pass (note if relevant)
[Check 3]: × fail — [reason]
[Check 4]: √ pass
[Criteria]: √ N/M met
____________________________
Result: PASS | FAIL | PARTIAL
根据步骤实际验证的内容调整检查项名称。通过使用 √,失败使用 ×,添加简短说明使用 —。“Criteria”行概述满足了多少项验收标准。“Result”行给出总体结论。
分支设置阶段检查项: Feature branch created、Base coverage measured
分析阶段检查项: Coverage report parsed、Gaps identified、Priority ranked
测试编写阶段检查项: Tests written、Self-check passed、No network, DB, clock, randomness, or sleep、Framework conventions followed
验证阶段检查项: Tests pass、New tests pass on their own、Coverage improved、No regressions
指南
- 遵循项目现有的测试模式和命名约定。
- 将新测试添加到已有的单元测试文件中。如果没有,则将它们放在项目的单元测试目录中,与源代码并列(Go
_test.go、Rust#[cfg(test)]模块)。切勿将它们添加到集成测试或 E2E 测试套件中。