tdd-workflow

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Test-Driven Development (TDD) Workflow

测试驱动开发(TDD)工作流

A disciplined approach to development where tests drive design and implementation.
一种以测试驱动设计与实现的严谨开发方法。

The TDD Mantra

TDD准则

"Never write a line of code without a failing test."
"在写出失败的测试之前,绝不编写任何代码。"

The RED-GREEN-REFACTOR Cycle

RED-GREEN-REFACTOR循环

RED Phase: Write a Failing Test

RED阶段:编写失败的测试

Goal: Define the expected behavior BEFORE implementation.
Rules:
  1. Write the smallest test that fails
  2. Test must fail for the RIGHT reason
  3. Test should clearly express intent
  4. Don't write implementation yet
Example:
typescript
// RED: Test the behavior we want
describe("Calculator", () => {
  it("should add two numbers", () => {
    const calc = new Calculator();
    expect(calc.add(2, 3)).toBe(5);
  });
});

// Run: npm test
// Result: FAIL - Calculator is not defined
// This is RED ✓
Checklist:
  • Test is written
  • Test fails when run
  • Failure message is clear
  • Test name describes expected behavior

目标:在实现代码之前,先定义预期行为。
规则
  1. 编写最小规模的失败测试
  2. 测试必须因正确的原因失败
  3. 测试应清晰表达意图
  4. 暂不编写实现代码
示例
typescript
// RED: Test the behavior we want
describe("Calculator", () => {
  it("should add two numbers", () => {
    const calc = new Calculator();
    expect(calc.add(2, 3)).toBe(5);
  });
});

// Run: npm test
// Result: FAIL - Calculator is not defined
// This is RED ✓
检查清单
  • 已编写测试
  • 运行测试时失败
  • 失败信息清晰明确
  • 测试名称描述了预期行为

GREEN Phase: Make the Test Pass

GREEN阶段:让测试通过

Goal: Write the MINIMUM code to pass the test.
Rules:
  1. Do the simplest thing that works
  2. Don't add extra features
  3. Don't optimize
  4. Just make it green
Example:
typescript
// GREEN: Minimum implementation to pass
class Calculator {
  add(a: number, b: number): number {
    return a + b; // Simplest thing that works
  }
}

// Run: npm test
// Result: PASS
// This is GREEN ✓
Checklist:
  • Test passes
  • No extra code added
  • Implementation is minimal

目标:编写最少的代码使测试通过。
规则
  1. 采用最简单可行的实现方式
  2. 不添加额外功能
  3. 不进行优化
  4. 只需让测试变绿(通过)
示例
typescript
// GREEN: Minimum implementation to pass
class Calculator {
  add(a: number, b: number): number {
    return a + b; // Simplest thing that works
  }
}

// Run: npm test
// Result: PASS
// This is GREEN ✓
检查清单
  • 测试已通过
  • 未添加多余代码
  • 实现保持最小化

REFACTOR Phase: Improve the Code

REFACTOR阶段:优化代码

Goal: Clean up while keeping tests green.
Rules:
  1. Only refactor with passing tests
  2. Run tests after each change
  3. Improve design, not behavior
  4. Small, incremental changes
Examples of refactoring:
  • Extract methods
  • Rename for clarity
  • Remove duplication
  • Improve performance
  • Add types/documentation
Checklist:
  • Tests still pass
  • Code is cleaner
  • No behavior changed
  • Ready for next RED

目标:在保持测试通过的前提下清理代码。
规则
  1. 仅在测试通过时进行重构
  2. 每次修改后运行测试
  3. 优化设计而非改变行为
  4. 采用小步、增量式的修改
重构示例
  • 提取方法
  • 重命名以提升可读性
  • 消除重复代码
  • 提升性能
  • 添加类型/文档
检查清单
  • 测试仍能通过
  • 代码更加简洁
  • 未改变原有行为
  • 为下一个RED阶段做好准备

TDD in Practice

TDD实践指南

Starting a New Feature

启动新功能

1. Write high-level acceptance test (may not run yet)
2. Write first unit test (RED)
3. Implement minimum code (GREEN)
4. Refactor if needed (REFACTOR)
5. Repeat 2-4 until feature complete
6. Verify acceptance test passes
1. 编写高层级验收测试(可能暂无法运行)
2. 编写首个单元测试(RED阶段)
3. 实现最小化代码(GREEN阶段)
4. 如有需要进行重构(REFACTOR阶段)
5. 重复步骤2-4直至功能完成
6. 验证验收测试通过

Test Structure (AAA Pattern)

测试结构(AAA模式)

typescript
it("should [behavior] when [condition]", () => {
  // Arrange - Set up test data and dependencies
  const user = createTestUser({ role: "admin" });
  const service = new UserService();

  // Act - Execute the code under test
  const result = service.getPermissions(user);

  // Assert - Verify expected outcomes
  expect(result).toContain("delete");
  expect(result).toContain("edit");
});
typescript
it("should [behavior] when [condition]", () => {
  // Arrange - 设置测试数据与依赖项
  const user = createTestUser({ role: "admin" });
  const service = new UserService();

  // Act - 执行待测试代码
  const result = service.getPermissions(user);

  // Assert - 验证预期结果
  expect(result).toContain("delete");
  expect(result).toContain("edit");
});

Test Naming Convention

测试命名规范

[Unit]_[Scenario]_[ExpectedResult]
Examples:
  • add_withPositiveNumbers_returnsSum
  • login_withInvalidPassword_throwsAuthError
  • getUser_whenNotFound_returnsNull

[单元]_[场景]_[预期结果]
示例:
  • add_withPositiveNumbers_returnsSum
  • login_withInvalidPassword_throwsAuthError
  • getUser_whenNotFound_returnsNull

Test Categories

测试分类

Unit Tests

单元测试

  • Single function/class in isolation
  • Mock all dependencies
  • Fast (<10ms per test)
  • Run constantly during development
  • 孤立测试单个函数/类
  • 模拟所有依赖项
  • 执行速度快(每个测试<10ms)
  • 开发过程中持续运行

Integration Tests

集成测试

  • Multiple components together
  • Real database (test instance)
  • Slower but more realistic
  • Run before commits
  • 测试多个组件协同工作
  • 使用真实数据库(测试实例)
  • 速度较慢但更贴近真实场景
  • 提交代码前运行

End-to-End Tests

端到端测试

  • Full system through UI
  • Slowest, most realistic
  • Run in CI/CD pipeline
  • Cover critical user paths

  • 通过UI测试完整系统
  • 速度最慢、最贴近真实场景
  • 在CI/CD流水线中运行
  • 覆盖关键用户路径

TDD Best Practices

TDD最佳实践

DO:

建议:

  • Start with the simplest case
  • Write one test at a time
  • Keep tests independent
  • Test behavior, not implementation
  • Use descriptive test names
  • Commit after each green
  • 从最简单的场景入手
  • 一次编写一个测试
  • 保持测试的独立性
  • 测试行为而非实现细节
  • 使用描述性的测试名称
  • 每次测试变绿后提交代码

DON'T:

避免:

  • Write code before tests
  • Test private methods directly
  • Test framework code
  • Overfit tests to implementation
  • Skip the refactor phase

  • 在编写测试前先写代码
  • 直接测试私有方法
  • 测试框架代码
  • 过度贴合实现细节编写测试
  • 跳过重构阶段

Edge Cases to Test

需测试的边缘场景

Always test:
  • Empty inputs (null, undefined, [], {}, '')
  • Boundary values (0, -1, MAX_INT, min/max dates)
  • Error conditions (network fail, invalid input)
  • Permission boundaries
  • Concurrent access
  • Unicode/special characters

务必测试以下场景:
  • 空输入(null, undefined, [], {}, '')
  • 边界值(0, -1, MAX_INT, 最小/最大日期)
  • 错误条件(网络故障、无效输入)
  • 权限边界
  • 并发访问
  • Unicode/特殊字符

Test Coverage Guidelines

测试覆盖率指南

MetricMinimumTarget
Statements70%85%
Branches70%80%
Functions80%90%
Lines70%85%
Coverage is a metric, not a goal. 100% coverage doesn't mean bug-free.

指标最小值目标值
语句覆盖率70%85%
分支覆盖率70%80%
函数覆盖率80%90%
行覆盖率70%85%
覆盖率是一个指标而非目标。100%覆盖率不代表没有bug。

Quick Reference

快速参考

RED    → Write failing test (define behavior)
GREEN  → Minimum code to pass (make it work)
REFACTOR → Clean up (make it right)
COMMIT → Save progress (make it permanent)

RED    → 编写失败的测试(定义行为)
GREEN  → 编写最小代码使测试通过(让它工作)
REFACTOR → 清理代码(让它更优)
COMMIT → 保存进度(固化成果)

Common TDD Mistakes

常见TDD误区

MistakeProblemSolution
Testing implementationBrittle testsTest behavior/outcomes
Tests too largeHard to debugSmaller, focused tests
Shared stateFlaky testsIsolate each test
Slow testsSkipped testsMock external deps
Testing obvious codeWasted timeFocus on logic
误区问题解决方案
测试实现细节测试用例脆弱测试行为/输出结果
测试用例过于庞大难以调试编写更小、聚焦的测试用例
共享状态测试用例不稳定隔离每个测试用例
测试执行速度慢被跳过不执行模拟外部依赖项
测试显而易见的代码浪费时间聚焦业务逻辑测试