关于 common-test-driven-development
common-test-driven-development 是指导代码开发采用测试驱动开发的技能,适用于新增功能、修复缺陷和重构。它要求先编写单个失败测试,再以最小实现通过测试,并在重构后运行相关测试。
主要功能
- 01先检查并运行现有测试
- 02先编写一个失败测试
- 03以最小实现使测试通过
- 04保持测试通过进行重构
- 05覆盖相关边界与错误情况
- 06完成后运行相关测试套件
适用场景
- 01为新函数或模块实现添加测试
- 02复现并修复已知缺陷
- 03重构业务逻辑并检查回归
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ xip-online-applications/ skills --skill common-test-driven-development安装后在 Claude Code 中输入/common-test-driven-development确认已加载。
详细介绍
common-test-driven-development
在编写实现代码之前或同时编写单元测试,遵循测试驱动开发方法,以确保正确性并防止回归。
使用时机
在以下情况下使用此技能:
- 创建新的函数、类、方法或模块
- 修改现有业务逻辑或行为
- 修复错误(先编写一个能复现该错误的失败测试)
- 重构代码(确保修改前后测试都存在且通过)
- 用户要求实现任何功能或逻辑
说明
-
先检查现有测试。 在编写任何实现代码之前,搜索代码库中与即将修改的代码相关的现有测试文件。
- 查找符合
*.test.*、*.spec.*、*_test.*、test_*.*等模式的文件,或tests//__tests__/目录。 - 如果发现现有测试,请运行它们。如果通过,请保留这些测试;除非断言因有意的行为变更而不再有效,否则不要修改通过的测试。
- 如果现有测试因断言反映的旧行为与新要求冲突而失败,只更新相关的特定断言。绝不要一次性删除或重写整套测试。
- 查找符合
-
先编写一个简单的失败测试。 在实现任何逻辑之前:
- 创建一个尽可能精简的单元测试,描述预期行为。
- 测试必须可以运行,并且必须失败(红灯阶段),因为实现尚不存在或不满足新要求。
- 为测试起一个能清楚描述所验证行为的名称(例如,
it should return the sum of two numbers或test_empty_list_returns_none)。 - 不要一次编写多个测试——从一个测试开始。
-
用最精简的实现让测试通过。 只编写足以让失败测试通过的生产代码(绿灯阶段)。
- 不要添加测试尚未要求的功能。
- 此阶段不要过度设计或预先考虑未来需求。
- 运行测试以确认其通过。
-
在保持测试通过的前提下重构。 测试通过后:
- 在不改变行为的前提下,改进代码结构、命名或重复代码。
- 重构后运行所有相关测试,确认没有问题。
-
针对后续行为重复此流程。 对于每一项新行为:
- 编写一个新的失败测试。
- 通过最精简的改动让测试通过。
- 如有需要则进行重构。
- 持续进行,直到完整满足要求。
-
测试质量规则。
- 每个测试必须只验证一种行为或场景。
- 测试必须彼此独立——不能共享可变状态,也不能依赖执行顺序。
- 使用读起来像规格说明的描述性测试名称。
- 优先测试公共接口,而非内部实现细节。
- 避免对所有内容都使用模拟——仅模拟外部依赖(I/O、网络、数据库、时钟)。
- 保持测试快速——单元测试不得依赖网络、文件系统或数据库。
-
测试结构。 遵循 Arrange-Act-Assert(AAA)或 Given-When-Then 模式:
- Arrange/Given:设置输入和依赖项。
- Act/When:调用被测单元。
- Assert/Then:验证输出或副作用。
-
边界情况。 在正常路径测试通过后,为以下情况添加测试:
- 边界值(空集合、零、null/undefined、最大值)。
- 错误情况(无效输入、缺失数据、异常)。
- 只为与具体实现逻辑相关的边界情况添加测试。
-
运行所有相关测试套件。 完成所有更改后,运行受影响模块或软件包的完整测试套件,确保没有回归。
-
绝不要为了节省时间而跳过测试。 编写代码时,就要编写测试。生产代码绝不能在没有相应测试的情况下编写。如果时间紧迫,请缩小范围——但实现范围内的每一行代码都必须有测试覆盖。
示例
简单函数的 TDD 循环
Step 1 — Write failing test:
test("adds two positive numbers", () => {
expect(add(2, 3)).toBe(5);
});
Step 2 — Minimal implementation:
function add(a, b) {
return a + b;
}
Step 3 — Test passes. Refactor if needed (nothing to refactor here).
Step 4 — Next test:
test("returns 0 when both arguments are 0", () => {
expect(add(0, 0)).toBe(0);
});
Step 5 — Already passes. Move to next behavior.
Handling existing tests
Scenario: You need to change a function's return type from number to string.
1. Run existing tests — they pass.
2. Identify which assertions will break due to the intentional change.
3. Update ONLY those assertions to expect the new string return type.
4. Confirm updated tests fail (since implementation hasn't changed yet).
5. Change the implementation.
6. Confirm all tests pass.
评论
支持 Markdown