test-driven-development
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTest-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 permissionsGiven: 拥有管理员权限的用户
When: 他们尝试访问受保护资源
Then: 授予访问权限并分配相应权限Test Naming Conventions
测试命名规范
Pattern: test_should_<expected_behavior>_when_<condition>
test_should_<expected_behavior>_when_<condition>模式:test_should_<预期行为>_when_<条件>
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.50JavaScript (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.50JavaScript (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
undefinedpython
undefinedGood: 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
undefineddef test_validation():
assert is_valid_email("user@example.com") is True
assert is_valid_phone("123-456-7890") is True # 不同概念
undefined2. Test Independence
2. 测试独立性
python
undefinedpython
undefinedGood: 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"
undefinedshared_user = None
def test_create_user():
global shared_user
shared_user = create_user("test@example.com")
def test_update_user(): # 依赖前一个测试
shared_user.name = "Updated"
undefined3. Descriptive Test Failures
3. 描述性测试失败信息
python
undefinedpython
undefinedGood: 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
undefinedassert result.status == 200
undefined4. Test Data Builders
4. 测试数据构建器
python
undefinedpython
undefinedGood: 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')
undefinedadmin = create_test_user(role='admin')
guest = create_test_user(email='guest@example.com')
undefinedTesting Anti-Patterns to Avoid
需避免的测试反模式
❌ Testing Implementation Details
❌ 测试实现细节
python
undefinedpython
undefinedBad: Tests internal structure
不良:测试内部结构
def test_user_storage():
user = User("test@example.com")
assert user._internal_cache is not None # Implementation detail
undefineddef test_user_storage():
user = User("test@example.com")
assert user._internal_cache is not None # 实现细节
undefined❌ Fragile Tests
❌ 脆弱测试
python
undefinedpython
undefinedBad: 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"
undefineddata = json.loads(user.to_json())
assert data['name'] == "John"
assert data['email'] == "john@example.com"
undefined❌ Slow Tests in Unit Test Suite
❌ 单元测试套件中包含慢测试
python
undefinedpython
undefinedBad: 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
undefineddef test_api_integration():
response = requests.get("https://api.example.com/users") # 速度慢!
assert response.status_code == 200
undefined❌ Testing Everything Through UI
❌ 完全通过UI测试所有内容
python
undefinedpython
undefinedBad: 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
undefineddef test_calculation():
assert calculate(5, 3) == 8
undefinedQuick Reference by Language
按语言快速参考
Python (pytest)
Python (pytest)
python
undefinedpython
undefinedSetup/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
undefinedJavaScript (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端点与依赖注入
[若你的技能包中已部署这些技能,可查看完整文档]