测试驱动开发技能Skill tdd

测试驱动开发技能旨在指导用户使用红绿重构周期进行严格的测试优先开发,帮助用户练习TDD、先写测试后写代码、开发新功能并优化测试结构。包含关键词如测试驱动开发、TDD、红绿重构、单元测试、集成测试、测试设计,适合SEO搜索用于软件开发中的测试环节。

测试 0 次安装 0 次浏览 更新于 3/12/2026

name: tdd description: | 使用红绿重构周期的测试驱动开发促进。引导用户先写测试,实现最小化代码通过,并重构以提高质量。当用户想要练习TDD、需要先写测试、以测试为先开发新功能或需要测试结构和实现指导时使用。触发词包括’使用TDD’、‘测试驱动开发’、‘先写测试’、'红绿重构’或请求用测试开发功能。 allowed-tools: “*”

测试驱动开发 (TDD) 技能

使用红绿重构周期引导用户进行严格的测试优先开发。

核心 TDD 工作流程

红 → 绿 → 重构 → 重复

红:写一个失败的测试

  1. 识别下一个要实现的小行为
  2. 写测试指定该行为
  3. 运行测试以验证其因正确原因失败
  4. 如果测试意外通过,测试是错误的

绿:使其通过

  1. 写最小代码以使测试通过
  2. 不要担心完美性
  3. 最简单的解决方案
  4. 运行测试以验证其通过

重构:改进代码

  1. 改进代码质量同时保持测试通过
  2. 移除重复
  3. 改进名称和结构
  4. 每次更改后运行测试以确保仍然通过

重复

  1. 测试通过时提交
  2. 识别下一个行为
  3. 从新测试开始下一个周期

TDD 纪律

要遵循的关键规则:

测试优先(红阶段)

  • 总是在实现前写测试
  • 抵制先写代码的冲动
  • 测试定义了什么意味着“完成”
  • 在使其通过前看到测试失败

最小实现(绿阶段)

  • 写最简单的代码以通过
  • 不要过度工程化
  • 不要添加未测试的功能
  • 一次一个测试

仅在绿时重构

  • 不要在有失败测试时重构
  • 在重构期间保持测试通过
  • 小的、增量式改进
  • 每次重构步骤后运行测试

频繁运行测试

  • 写测试后(应失败)
  • 写实现后(应通过)
  • 每次重构步骤后(应保持通过)
  • 提交前

何时使用此技能

为涉及以下请求激活:

  • “使用TDD…” / “测试驱动开发…”
  • “先写测试…” / “红绿重构…”
  • 以测试为先开发新功能
  • 学习TDD实践
  • 设置测试基础设施
  • 测试设计和组织

测试结构模式

安排-执行-断言 (AAA)

安排 - 设置测试数据和环境 执行 - 执行被测试的代码 断言 - 验证结果

def test_add_two_numbers():
    calculator = Calculator()           # 安排
    result = calculator.add(2, 3)      # 执行
    assert result == 5                  # 断言

给定-当-则 (BDD 风格)

给定 - 初始上下文/前提条件 - 发生动作/事件 - 预期结果

测试设计原则

测试什么

  • 公共接口 - 测试用户依赖的行为
  • 边缘情况 - 边界、空输入、最大值
  • 错误条件 - 无效输入、异常
  • 业务逻辑 - 核心算法和规则
  • 集成点 - 组件交互处

不测试什么

  • 私有实现细节 - 测试行为而非内部
  • 第三方库 - 信任它们工作,测试你的使用
  • 简单getter/setter - 除非它们有逻辑
  • 框架代码 - 测试你的代码,而非框架

每个测试一个行为

  • 每个测试应验证单一行为
  • 使故障更易诊断
  • 保持测试专注和可读
  • 首选多个小测试而非一个大测试

使测试可读

  • 描述性名称 - test_add_returns_sum_of_two_positive_numbers
  • 清晰结构 - AAA 或给定-当-则
  • 自文档化 - 测试显示代码应如何使用
  • 最小设置 - 仅此测试所需

保持测试独立

  • 测试不应相互依赖
  • 测试可以任意顺序运行
  • 每个测试从清洁状态开始
  • 测试间无共享可变状态

参见 references/test-design-patterns.md 获取全面指导。

语言特定指导

对于 Python

参见 references/python-tdd.md 获取:

  • pytest 和 unittest 框架
  • 装置和参数化测试
  • 使用 unittest.mock 模拟
  • 测试异步代码
  • 使用 pytest-cov 覆盖
  • 运行和组织测试

对于 Emacs Lisp

参见 references/elisp-tdd.md 获取:

  • ERT (Emacs Lisp 回归测试)
  • 测试交互函数
  • 缓冲区操作测试
  • 使用 cl-letf 模拟
  • Buttercup (BDD 替代)
  • 在 Emacs 和批处理模式运行测试

对于其他语言

参见 references/general-tdd.md 获取:

  • 查找测试框架
  • 通用测试模式
  • 常见测试概念
  • 构建工具集成
  • 语言无关原则

测试类型及何时使用

单元测试

什么: 隔离测试单个函数/方法

何时:

  • 测试纯函数
  • 测试业务逻辑
  • 测试算法
  • 快速、专注的测试

示例: test_calculate_discount(price, percentage)

集成测试

什么: 测试多个组件协同工作

何时:

  • 测试数据库交互
  • 测试 API 调用
  • 测试服务集成
  • 验证组件正确连接

示例: test_user_service_saves_to_database()

端到端测试

什么: 测试完整用户工作流

何时:

  • 测试关键用户路径
  • 验证系统整体
  • 部署冒烟测试

示例: test_user_can_register_and_login()

测试金字塔:

      /\      ← 少端到端测试(慢、脆弱)
     /  \
    / IT \    ← 一些集成测试
   /______\
  /  单元  \  ← 多单元测试(快速、专注)
 /__________\

TDD 红绿重构示例

目标: 实现阶乘函数

迭代 1 - 基本案例:

  • 红:test_factorial_of_zero_is_one() → ❌ 阶乘未定义
  • 绿:def factorial(n): return 1 → ✅ 通过
  • 重构:暂无。提交。

迭代 2 - 正数:

  • 红:test_factorial_of_five() 期望 120 → ❌ 得到 1
  • 绿:实现循环计算阶乘 → ✅ 通过
  • 重构:使用递归以提高优雅性 → ✅ 仍然通过。提交。

迭代 3 - 错误处理:

  • 红:test_factorial_negative_raises_error() → ❌ 未引发错误
  • 绿:添加 if n < 0: raise ValueError → ✅ 所有测试通过
  • 重构:添加文档字符串 → ✅ 仍然通过。提交。

完成! 函数完整、全测试、文档化。三个测试驱动迭代。

模拟和测试替身

何时模拟

  • 外部依赖 - 数据库、API、文件系统
  • 慢操作 - 网络调用、大计算
  • 不可预测行为 - 随机、时间依赖、外部状态
  • 难触发场景 - 错误条件、边缘案例

何时不模拟

  • 你自己的代码 - 首选真实对象用于你的代码
  • 简单对象 - 数据类、值对象
  • 被测试逻辑 - 不要模拟你正在测试的内容

测试替身类型

模拟 - 用期望编程,验证交互 存根 - 提供固定响应,不验证 伪造 - 工作实现,比真实简单 间谍 - 记录调用,允许后验证

参见 references/test-design-patterns.md 获取详细模拟策略。

常见 TDD 反模式

不要:

在测试前写实现 - 违背 TDD 目的

在使测试通过前写多个测试 - 保持节奏(一个测试,使其通过,下一个测试)

在红测试时重构 - 仅在绿时重构

测试实现细节 - 测试行为,而非内部

跳过重构步骤 - 技术债务积累

写难理解的测试 - 测试是文档

在测试间创建依赖 - 测试必须独立

模拟所有 - 实际时使用真实对象

永远用硬编码值假装 - “假装直到你实现”是临时的

写慢测试 - 慢测试套件不会频繁运行

测试命名约定

好测试名称是描述性和具体的:

模式:test_<函数>_<场景>_<预期结果>

test_add_two_positive_numbers_returns_sum()
test_add_with_negative_number_returns_correct_result()
test_add_with_zero_returns_other_number()

模式:should_<预期行为>_when_<条件>

should_return_empty_list_when_no_items_match()
should_raise_error_when_input_is_null()
should_calculate_discount_when_user_is_premium()

模式:<行为>_<状态>_<预期>

(ert-deftest save-buffer-modified-saves-to-file ())
(ert-deftest load-file-missing-raises-error ())

测试名称应:

  • 描述被测试内容
  • 描述场景/条件
  • 描述预期结果
  • 作为文档可读

测试组织

目录结构

Python:

项目/
├── src/
│   └── calculator.py
└── tests/
    ├── __init__.py
    ├── test_calculator.py
    └── conftest.py  # pytest 装置

Elisp:

包/
├── my-package.el
└── test/
    └── test-my-package.el

命名约定

  • 测试文件:test_*.py, *_test.py, test-*.el
  • 测试函数:以 test_ert-deftest 开头
  • 测试类:Test*(如果使用类)

分组测试

  • 一般每个源文件一个测试文件
  • 在同一文件中分组相关测试
  • 分离单元/集成/端到端测试

参见语言特定参考获取详细组织模式。

使用测试重构

安全重构过程

  1. 确保所有测试为绿 前开始
  2. 做小更改 - 一次重构
  3. 每次更改后运行测试 - 立即捕获中断
  4. 频繁提交 - 当测试通过时
  5. 重构时不添加功能 - 分离关注点

常见重构

  • 提取函数(分解大函数)
  • 重命名以提高清晰度
  • 移除重复(DRY)
  • 简化条件逻辑
  • 提取变量以提高可读性
  • 内联不必要抽象

重构时测试中断

如果测试实现细节:

  • 更新测试以测试行为
  • 使测试对更改更有弹性

如果测试行为:

  • 修复代码,而非测试
  • 重构期间行为不应改变

如果太多测试中断:

  • 更改太大,回滚
  • 做更小的增量更改

参见 references/refactoring-with-tests.md 获取详细指导。

测试覆盖

覆盖测量哪些代码由测试执行,而非测试是否好。

覆盖类型

  • 行覆盖 - 哪些行执行
  • 分支覆盖 - 哪些路径采取
  • 函数覆盖 - 哪些函数调用

覆盖目标

  • 目标高覆盖 (80%+) 但非 100%
  • 100% 覆盖不意味无错误
  • 关注关键代码路径
  • 不要仅为增加覆盖而测试

使用覆盖工具

  • Python: pytest-cov, coverage.py
  • JavaScript: Jest with coverage
  • Java: JaCoCo
  • Ruby: SimpleCov

使用 scripts/coverage_analyzer.py 识别覆盖缺口。

使用支持资源

本技能附加资源:

  • references/python-tdd.md: 全面 Python 测试指导(pytest, unittest, 模拟, 异步)
  • references/elisp-tdd.md: 全面 Elisp 测试指导(ERT, Buttercup, 交互函数)
  • references/general-tdd.md: 任何语言的通用 TDD 原则
  • references/test-design-patterns.md: 测试什么、测试组织、反模式
  • references/refactoring-with-tests.md: 安全重构过程和常见重构
  • scripts/test_template_generator.py: 生成测试文件模板
  • scripts/coverage_analyzer.py: 分析覆盖报告
  • assets/templates/: 多语言测试文件模板

快速参考

TDD 周期:

  1. 红 - 写失败测试
  2. 绿 - 使其通过(最小代码)
  3. 重构 - 改进同时保持绿
  4. 重复

测试结构:

  • 安排(设置)
  • 执行(执行)
  • 断言(验证)

测试原则:

  • 测试优先
  • 一次一个测试
  • 每个测试一个行为
  • 独立测试
  • 快速测试
  • 可读测试

重构规则:

  • 仅在绿时重构
  • 小更改
  • 频繁运行测试
  • 不添加功能

记住: TDD 是纪律。价值来自严格遵循周期。先测试。看到失败。使其通过。重构。重复。节奏创造质量代码。