test-driven-development

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Test-Driven Development (TDD)

测试驱动开发(TDD)

Comprehensive TDD patterns and practices for all programming languages. This skill eliminates ~500-800 lines of redundant testing guidance per agent.
适用于所有编程语言的全面TDD模式与实践。该技能可为每个Agent减少约500-800行冗余测试指导。

When to Use

适用场景

Apply TDD for:
  • New feature implementation
  • Bug fixes (test the bug first)
  • Code refactoring (tests ensure behavior preservation)
  • API development (test contracts)
  • Complex business logic
在以下场景应用TDD:
  • 新功能实现
  • Bug修复(先针对Bug编写测试)
  • 代码重构(测试确保行为一致性)
  • API开发(测试契约)
  • 复杂业务逻辑

TDD Workflow (Red-Green-Refactor)

TDD工作流(红-绿-重构)

1. Red Phase: Write Failing Test

1. 红阶段:编写失败的测试

Write a test that:
- Describes the desired behavior
- Fails for the right reason (not due to syntax errors)
- Is focused on a single behavior
编写满足以下要求的测试:
- 描述期望的行为
- 因正确的原因失败(而非语法错误)
- 聚焦单一行为

2. Green Phase: Make It Pass

2. 绿阶段:让测试通过

Write the minimum code to:
- Pass the test
- Not introduce regressions
- Follow existing patterns
编写最少代码以:
- 通过测试
- 不引入回归问题
- 遵循现有模式

3. Refactor Phase: Improve Code

3. 重构阶段:优化代码

While keeping tests green:
- Remove duplication
- Improve naming
- Simplify logic
- Extract functions/classes
在保持测试通过的前提下:
- 消除重复代码
- 优化命名
- 简化逻辑
- 提取函数/类

Test Structure Patterns

测试结构模式

Arrange-Act-Assert (AAA)

准备-执行-断言(AAA)

// Arrange: Set up test data and conditions
const user = createTestUser({ role: 'admin' });

// Act: Perform the action being tested
const result = await authenticateUser(user);

// Assert: Verify the outcome
expect(result.isAuthenticated).toBe(true);
expect(result.permissions).toContain('admin');
// Arrange: 设置测试数据和条件
const user = createTestUser({ role: 'admin' });

// Act: 执行待测试的操作
const result = await authenticateUser(user);

// Assert: 验证结果
expect(result.isAuthenticated).toBe(true);
expect(result.permissions).toContain('admin');

Given-When-Then (BDD Style)

给定-当-则(BDD风格)

Given: A user with admin privileges
When: They attempt to access protected resource
Then: Access is granted with appropriate permissions
Given: 拥有管理员权限的用户
When: 他们尝试访问受保护资源
Then: 授予访问权限并分配相应权限

Test Naming Conventions

测试命名规范

Pattern:
test_should_<expected_behavior>_when_<condition>

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

Examples:
  • test_should_return_user_when_id_exists()
  • test_should_raise_error_when_user_not_found()
  • test_should_validate_email_format_when_creating_account()
示例:
  • test_should_return_user_when_id_exists()
  • test_should_raise_error_when_user_not_found()
  • test_should_validate_email_format_when_creating_account()

Language-Specific Conventions

语言特定规范

Python (pytest):
python
def test_should_calculate_total_when_items_added():
    # Arrange
    cart = ShoppingCart()
    cart.add_item(Item("Book", 10.00))
    cart.add_item(Item("Pen", 1.50))

    # Act
    total = cart.calculate_total()

    # Assert
    assert total == 11.50
JavaScript (Jest):
javascript
describe('ShoppingCart', () => {
  test('should calculate total when items added', () => {
    const cart = new ShoppingCart();
    cart.addItem({ name: 'Book', price: 10.00 });
    cart.addItem({ name: 'Pen', price: 1.50 });

    const total = cart.calculateTotal();

    expect(total).toBe(11.50);
  });
});
Go:
go
func TestShouldCalculateTotalWhenItemsAdded(t *testing.T) {
    // Arrange
    cart := NewShoppingCart()
    cart.AddItem(Item{Name: "Book", Price: 10.00})
    cart.AddItem(Item{Name: "Pen", Price: 1.50})

    // Act
    total := cart.CalculateTotal()

    // Assert
    if total != 11.50 {
        t.Errorf("Expected 11.50, got %f", total)
    }
}
Python (pytest):
python
def test_should_calculate_total_when_items_added():
    # Arrange
    cart = ShoppingCart()
    cart.add_item(Item("Book", 10.00))
    cart.add_item(Item("Pen", 1.50))

    # Act
    total = cart.calculate_total()

    # Assert
    assert total == 11.50
JavaScript (Jest):
javascript
describe('ShoppingCart', () => {
  test('should calculate total when items added', () => {
    const cart = new ShoppingCart();
    cart.addItem({ name: 'Book', price: 10.00 });
    cart.addItem({ name: 'Pen', price: 1.50 });

    const total = cart.calculateTotal();

    expect(total).toBe(11.50);
  });
});
Go:
go
func TestShouldCalculateTotalWhenItemsAdded(t *testing.T) {
    // Arrange
    cart := NewShoppingCart()
    cart.AddItem(Item{Name: "Book", Price: 10.00})
    cart.AddItem(Item{Name: "Pen", Price: 1.50})

    // Act
    total := cart.CalculateTotal()

    // Assert
    if total != 11.50 {
        t.Errorf("Expected 11.50, got %f", total)
    }
}

Test Types and Scope

测试类型与范围

Unit Tests

单元测试

  • Scope: Single function/method
  • Dependencies: Mocked
  • Speed: Fast (< 10ms per test)
  • Coverage: 80%+ of code paths
  • 范围: 单个函数/方法
  • 依赖: 已Mock
  • 速度: 快(每个测试<10ms)
  • 覆盖率: 代码路径的80%+

Integration Tests

集成测试

  • Scope: Multiple components
  • Dependencies: Real or test doubles
  • Speed: Moderate (< 1s per test)
  • Coverage: Critical paths and interfaces
  • 范围: 多个组件
  • 依赖: 真实对象或测试替身
  • 速度: 中等(每个测试<1s)
  • 覆盖率: 关键路径与接口

End-to-End Tests

端到端测试

  • Scope: Full user workflows
  • Dependencies: Real (in test environment)
  • Speed: Slow (seconds to minutes)
  • Coverage: Core user journeys
  • 范围: 完整用户流程
  • 依赖: 真实环境(测试环境中)
  • 速度: 慢(几秒到几分钟)
  • 覆盖率: 核心用户旅程

Mocking and Test Doubles

Mocking与测试替身

When to Mock

何时使用Mock

  • External APIs and services
  • Database operations (for unit tests)
  • File system operations
  • Time-dependent operations
  • Random number generation
  • 外部API与服务
  • 数据库操作(单元测试中)
  • 文件系统操作
  • 时间相关操作
  • 随机数生成

Mock Types

Mock类型

Stub: Returns predefined data
python
def get_user_stub(user_id):
    return User(id=user_id, name="Test User")
Mock: Verifies interactions
python
mock_service = Mock()
service.process_payment(payment_data)
mock_service.process_payment.assert_called_once_with(payment_data)
Fake: Working implementation (simplified)
python
class FakeDatabase:
    def __init__(self):
        self.data = {}

    def save(self, key, value):
        self.data[key] = value

    def get(self, key):
        return self.data.get(key)
Stub: 返回预定义数据
python
def get_user_stub(user_id):
    return User(id=user_id, name="Test User")
Mock: 验证交互
python
mock_service = Mock()
service.process_payment(payment_data)
mock_service.process_payment.assert_called_once_with(payment_data)
Fake: 可用的简化实现
python
class FakeDatabase:
    def __init__(self):
        self.data = {}

    def save(self, key, value):
        self.data[key] = value

    def get(self, key):
        return self.data.get(key)

Test Coverage Guidelines

测试覆盖率指南

Target Coverage Levels

目标覆盖率水平

  • Critical paths: 100%
  • Business logic: 95%+
  • Overall project: 80%+
  • UI components: 70%+
  • 关键路径: 100%
  • 业务逻辑: 95%+
  • 整体项目: 80%+
  • UI组件: 70%+

What to Test

测试内容

  • ✅ Business logic and algorithms
  • ✅ Edge cases and boundary conditions
  • ✅ Error handling and validation
  • ✅ State transitions
  • ✅ Public APIs and interfaces
  • ✅ 业务逻辑与算法
  • ✅ 边缘情况与边界条件
  • ✅ 错误处理与验证
  • ✅ 状态转换
  • ✅ 公共API与接口

What NOT to Test

无需测试内容

  • ❌ Framework internals
  • ❌ Third-party libraries
  • ❌ Trivial getters/setters
  • ❌ Generated code
  • ❌ Configuration files
  • ❌ 框架内部实现
  • ❌ 第三方库
  • ❌ 简单的getter/setter
  • ❌ 生成代码
  • ❌ 配置文件

Testing Best Practices

测试最佳实践

1. One Assertion Per Test (When Possible)

1. 每个测试尽可能仅含一个断言

python
undefined
python
undefined

Good: Focused test

良好:聚焦单一测试点

def test_should_validate_email_format(): assert is_valid_email("user@example.com") is True
def test_should_validate_email_format(): assert is_valid_email("user@example.com") is True

Avoid: Multiple unrelated assertions

避免:多个不相关断言

def test_validation(): assert is_valid_email("user@example.com") is True assert is_valid_phone("123-456-7890") is True # Different concept
undefined
def test_validation(): assert is_valid_email("user@example.com") is True assert is_valid_phone("123-456-7890") is True # 不同概念
undefined

2. Test Independence

2. 测试独立性

python
undefined
python
undefined

Good: Each test is self-contained

良好:每个测试自包含

def test_user_creation(): user = create_user("test@example.com") assert user.email == "test@example.com"
def test_user_creation(): user = create_user("test@example.com") assert user.email == "test@example.com"

Avoid: Tests depending on execution order

避免:测试依赖执行顺序

shared_user = None
def test_create_user(): global shared_user shared_user = create_user("test@example.com")
def test_update_user(): # Depends on previous test shared_user.name = "Updated"
undefined
shared_user = None
def test_create_user(): global shared_user shared_user = create_user("test@example.com")
def test_update_user(): # 依赖前一个测试 shared_user.name = "Updated"
undefined

3. Descriptive Test Failures

3. 描述性测试失败信息

python
undefined
python
undefined

Good: Clear failure message

良好:清晰的失败信息

assert result.status == 200, f"Expected 200, got {result.status}: {result.body}"
assert result.status == 200, f"预期状态码200,实际得到{result.status}: {result.body}"

Avoid: Unclear failure

避免:模糊的失败信息

assert result.status == 200
undefined
assert result.status == 200
undefined

4. Test Data Builders

4. 测试数据构建器

python
undefined
python
undefined

Good: Reusable test data creation

良好:可复用的测试数据创建函数

def create_test_user(overrides): defaults = { 'email': 'test@example.com', 'name': 'Test User', 'role': 'user' } return User({**defaults, **overrides})
def create_test_user(overrides): defaults = { 'email': 'test@example.com', 'name': 'Test User', 'role': 'user' } return User({**defaults, **overrides})

Usage

使用示例

admin = create_test_user(role='admin') guest = create_test_user(email='guest@example.com')
undefined
admin = create_test_user(role='admin') guest = create_test_user(email='guest@example.com')
undefined

Testing Anti-Patterns to Avoid

需避免的测试反模式

❌ Testing Implementation Details

❌ 测试实现细节

python
undefined
python
undefined

Bad: Tests internal structure

不良:测试内部结构

def test_user_storage(): user = User("test@example.com") assert user._internal_cache is not None # Implementation detail
undefined
def test_user_storage(): user = User("test@example.com") assert user._internal_cache is not None # 实现细节
undefined

❌ Fragile Tests

❌ 脆弱测试

python
undefined
python
undefined

Bad: Breaks with harmless changes

不良:无关修改会导致测试失败

assert user.to_json() == '{"name":"John","email":"john@example.com"}'
assert user.to_json() == '{"name":"John","email":"john@example.com"}'

Good: Tests behavior, not format

良好:测试行为而非格式

data = json.loads(user.to_json()) assert data['name'] == "John" assert data['email'] == "john@example.com"
undefined
data = json.loads(user.to_json()) assert data['name'] == "John" assert data['email'] == "john@example.com"
undefined

❌ Slow Tests in Unit Test Suite

❌ 单元测试套件中包含慢测试

python
undefined
python
undefined

Bad: Real HTTP calls in unit tests

不良:单元测试中调用真实HTTP接口

def test_api_integration(): response = requests.get("https://api.example.com/users") # Slow! assert response.status_code == 200
undefined
def test_api_integration(): response = requests.get("https://api.example.com/users") # 速度慢! assert response.status_code == 200
undefined

❌ Testing Everything Through UI

❌ 完全通过UI测试所有内容

python
undefined
python
undefined

Bad: Testing business logic through UI

不良:通过UI测试业务逻辑

def test_calculation(): browser.click("#input1") browser.type("5") browser.click("#input2") browser.type("3") browser.click("#calculate") assert browser.find("#result").text == "8"
def test_calculation(): browser.click("#input1") browser.type("5") browser.click("#input2") browser.type("3") browser.click("#calculate") assert browser.find("#result").text == "8"

Good: Test logic directly

良好:直接测试逻辑

def test_calculation(): assert calculate(5, 3) == 8
undefined
def test_calculation(): assert calculate(5, 3) == 8
undefined

Quick Reference by Language

按语言快速参考

Python (pytest)

Python (pytest)

python
undefined
python
undefined

Setup/Teardown

前置/后置处理

@pytest.fixture def database(): db = create_test_database() yield db db.cleanup()
@pytest.fixture def database(): db = create_test_database() yield db db.cleanup()

Parametrized tests

参数化测试

@pytest.mark.parametrize("input,expected", [ ("user@example.com", True), ("invalid-email", False), ]) def test_email_validation(input, expected): assert is_valid_email(input) == expected
undefined
@pytest.mark.parametrize("input,expected", [ ("user@example.com", True), ("invalid-email", False), ]) def test_email_validation(input, expected): assert is_valid_email(input) == expected
undefined

JavaScript (Jest)

JavaScript (Jest)

javascript
// Setup/Teardown
beforeEach(() => {
  database = createTestDatabase();
});

afterEach(() => {
  database.cleanup();
});

// Async tests
test('should fetch user data', async () => {
  const user = await fetchUser(1);
  expect(user.name).toBe('John');
});
javascript
// 前置/后置处理
beforeEach(() => {
  database = createTestDatabase();
});

afterEach(() => {
  database.cleanup();
});

// 异步测试
test('should fetch user data', async () => {
  const user = await fetchUser(1);
  expect(user.name).toBe('John');
});

Go

Go

go
// Table-driven tests
func TestEmailValidation(t *testing.T) {
    tests := []struct {
        input    string
        expected bool
    }{
        {"user@example.com", true},
        {"invalid-email", false},
    }

    for _, tt := range tests {
        result := IsValidEmail(tt.input)
        if result != tt.expected {
            t.Errorf("IsValidEmail(%s) = %v, want %v",
                tt.input, result, tt.expected)
        }
    }
}
go
// 表格驱动测试
func TestEmailValidation(t *testing.T) {
    tests := []struct {
        input    string
        expected bool
    }{
        {"user@example.com", true},
        {"invalid-email", false},
    }

    for _, tt := range tests {
        result := IsValidEmail(tt.input)
        if result != tt.expected {
            t.Errorf("IsValidEmail(%s) = %v, want %v",
                tt.input, result, tt.expected)
        }
    }
}

TDD Benefits Realized

TDD带来的收益

  • Design Improvement: Tests drive better API design
  • Documentation: Tests serve as executable documentation
  • Confidence: Refactoring becomes safe
  • Debugging: Tests isolate issues quickly
  • Coverage: Ensures comprehensive test coverage
  • Regression Prevention: Catches bugs before deployment
  • 设计改进: 测试驱动更优的API设计
  • 文档: 测试可作为可执行文档
  • 信心: 重构变得安全
  • 调试: 测试可快速定位问题
  • 覆盖率: 确保全面的测试覆盖
  • 防回归: 部署前发现Bug

Related Skills

相关技能

When using Test Driven Development, these skills enhance your workflow:
  • systematic-debugging: Debug-first methodology when tests fail unexpectedly
  • react: Testing React components, hooks, and context
  • django: Testing Django models, views, and forms
  • fastapi-local-dev: Testing FastAPI endpoints and dependency injection
[Full documentation available in these skills if deployed in your bundle]
使用测试驱动开发时,以下技能可优化你的工作流:
  • systematic-debugging: 当测试意外失败时的调试优先方法论
  • react: 测试React组件、Hooks与上下文
  • django: 测试Django模型、视图与表单
  • fastapi-local-dev: 测试FastAPI端点与依赖注入
[若你的技能包中已部署这些技能,可查看完整文档]