mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-03-30 13:43:26 +08:00
331 lines
8.1 KiB
Markdown
331 lines
8.1 KiB
Markdown
---
|
||
description: 强制执行测试驱动开发工作流。首先搭建接口,生成测试,然后实现最小化代码以通过测试。确保 80%+ 覆盖率。
|
||
---
|
||
|
||
# TDD 命令
|
||
|
||
此命令调用 **tdd-guide** 代理来强制执行测试驱动开发方法。
|
||
|
||
## 此命令的作用
|
||
|
||
1. **搭建接口** - 首先定义类型/接口
|
||
2. **首先生成测试** - 编写失败的测试(红)
|
||
3. **实现最小化代码** - 编写刚好足够的代码以通过测试(绿)
|
||
4. **重构** - 改进代码,同时保持测试通过(重构)
|
||
5. **验证覆盖率** - 确保 80%+ 的测试覆盖率
|
||
|
||
## 何时使用
|
||
|
||
在以下情况下使用 `/tdd`:
|
||
|
||
* 实现新功能时
|
||
* 添加新函数/组件时
|
||
* 修复错误时(首先编写重现错误的测试)
|
||
* 重构现有代码时
|
||
* 构建关键业务逻辑时
|
||
|
||
## 工作原理
|
||
|
||
tdd-guide 代理将:
|
||
|
||
1. 为输入/输出**定义接口**
|
||
2. **编写将会失败的测试**(因为代码尚不存在)
|
||
3. **运行测试**并验证它们因正确的原因而失败
|
||
4. **编写最小化实现**以使测试通过
|
||
5. **运行测试**并验证它们通过
|
||
6. **重构**代码,同时保持测试通过
|
||
7. **检查覆盖率**,如果低于 80% 则添加更多测试
|
||
|
||
## TDD 循环
|
||
|
||
```
|
||
RED → GREEN → REFACTOR → REPEAT
|
||
|
||
RED: Write a failing test
|
||
GREEN: Write minimal code to pass
|
||
REFACTOR: Improve code, keep tests passing
|
||
REPEAT: Next feature/scenario
|
||
```
|
||
|
||
## 使用示例
|
||
|
||
````
|
||
User: /tdd I need a function to calculate market liquidity score
|
||
|
||
Agent (tdd-guide):
|
||
# TDD Session: Market Liquidity Score Calculator
|
||
|
||
## Step 1: Define Interface (SCAFFOLD)
|
||
|
||
```typescript
|
||
// lib/liquidity.ts
|
||
export interface MarketData {
|
||
totalVolume: number
|
||
bidAskSpread: number
|
||
activeTraders: number
|
||
lastTradeTime: Date
|
||
}
|
||
|
||
export function calculateLiquidityScore(market: MarketData): number {
|
||
// TODO: Implementation
|
||
throw new Error('Not implemented')
|
||
}
|
||
````
|
||
|
||
## 步骤 2:编写失败的测试(红)
|
||
|
||
```typescript
|
||
// lib/liquidity.test.ts
|
||
import { calculateLiquidityScore } from './liquidity'
|
||
|
||
describe('calculateLiquidityScore', () => {
|
||
it('should return high score for liquid market', () => {
|
||
const market = {
|
||
totalVolume: 100000,
|
||
bidAskSpread: 0.01,
|
||
activeTraders: 500,
|
||
lastTradeTime: new Date()
|
||
}
|
||
|
||
const score = calculateLiquidityScore(market)
|
||
|
||
expect(score).toBeGreaterThan(80)
|
||
expect(score).toBeLessThanOrEqual(100)
|
||
})
|
||
|
||
it('should return low score for illiquid market', () => {
|
||
const market = {
|
||
totalVolume: 100,
|
||
bidAskSpread: 0.5,
|
||
activeTraders: 2,
|
||
lastTradeTime: new Date(Date.now() - 86400000) // 1 day ago
|
||
}
|
||
|
||
const score = calculateLiquidityScore(market)
|
||
|
||
expect(score).toBeLessThan(30)
|
||
expect(score).toBeGreaterThanOrEqual(0)
|
||
})
|
||
|
||
it('should handle edge case: zero volume', () => {
|
||
const market = {
|
||
totalVolume: 0,
|
||
bidAskSpread: 0,
|
||
activeTraders: 0,
|
||
lastTradeTime: new Date()
|
||
}
|
||
|
||
const score = calculateLiquidityScore(market)
|
||
|
||
expect(score).toBe(0)
|
||
})
|
||
})
|
||
```
|
||
|
||
## 步骤 3:运行测试 - 验证失败
|
||
|
||
```bash
|
||
npm test lib/liquidity.test.ts
|
||
|
||
FAIL lib/liquidity.test.ts
|
||
✕ should return high score for liquid market (2 ms)
|
||
Error: Not implemented
|
||
|
||
1 test failed, 0 passed
|
||
```
|
||
|
||
✅ 测试按预期失败。准备实施。
|
||
|
||
## 步骤 4:实现最小化代码(绿)
|
||
|
||
```typescript
|
||
// lib/liquidity.ts
|
||
export function calculateLiquidityScore(market: MarketData): number {
|
||
// Handle zero volume edge case
|
||
if (market.totalVolume === 0) {
|
||
return 0
|
||
}
|
||
|
||
// Calculate component scores (0-100 scale)
|
||
const volumeScore = Math.min(market.totalVolume / 1000, 100)
|
||
const spreadScore = Math.max(100 - (market.bidAskSpread * 1000), 0)
|
||
const traderScore = Math.min(market.activeTraders / 10, 100)
|
||
|
||
// Recent activity bonus
|
||
const hoursSinceLastTrade = (Date.now() - market.lastTradeTime.getTime()) / (1000 * 60 * 60)
|
||
const recencyScore = Math.max(100 - (hoursSinceLastTrade * 10), 0)
|
||
|
||
// Weighted average
|
||
const score = (
|
||
volumeScore * 0.4 +
|
||
spreadScore * 0.3 +
|
||
traderScore * 0.2 +
|
||
recencyScore * 0.1
|
||
)
|
||
|
||
return Math.min(Math.max(score, 0), 100) // Clamp to 0-100
|
||
}
|
||
```
|
||
|
||
## 步骤 5:运行测试 - 验证通过
|
||
|
||
```bash
|
||
npm test lib/liquidity.test.ts
|
||
|
||
PASS lib/liquidity.test.ts
|
||
✓ should return high score for liquid market (3 ms)
|
||
✓ should return low score for illiquid market (2 ms)
|
||
✓ should handle edge case: zero volume (1 ms)
|
||
|
||
3 tests passed
|
||
```
|
||
|
||
✅ 所有测试通过!
|
||
|
||
## 步骤 6:重构(改进)
|
||
|
||
```typescript
|
||
// lib/liquidity.ts - Refactored with constants and better readability
|
||
const WEIGHTS = {
|
||
VOLUME: 0.4,
|
||
SPREAD: 0.3,
|
||
TRADERS: 0.2,
|
||
RECENCY: 0.1,
|
||
} as const
|
||
|
||
const SCALE_FACTORS = {
|
||
VOLUME: 1000,
|
||
SPREAD: 1000,
|
||
TRADERS: 10,
|
||
RECENCY_PENALTY: 10,
|
||
} as const
|
||
|
||
function clamp(value: number, min: number, max: number): number {
|
||
return Math.min(Math.max(value, min), max)
|
||
}
|
||
|
||
export function calculateLiquidityScore(market: MarketData): number {
|
||
if (market.totalVolume === 0) return 0
|
||
|
||
const volumeScore = Math.min(market.totalVolume / SCALE_FACTORS.VOLUME, 100)
|
||
const spreadScore = clamp(100 - (market.bidAskSpread * SCALE_FACTORS.SPREAD), 0, 100)
|
||
const traderScore = Math.min(market.activeTraders / SCALE_FACTORS.TRADERS, 100)
|
||
|
||
const hoursSinceLastTrade = (Date.now() - market.lastTradeTime.getTime()) / (1000 * 60 * 60)
|
||
const recencyScore = clamp(100 - (hoursSinceLastTrade * SCALE_FACTORS.RECENCY_PENALTY), 0, 100)
|
||
|
||
const weightedScore =
|
||
volumeScore * WEIGHTS.VOLUME +
|
||
spreadScore * WEIGHTS.SPREAD +
|
||
traderScore * WEIGHTS.TRADERS +
|
||
recencyScore * WEIGHTS.RECENCY
|
||
|
||
return clamp(weightedScore, 0, 100)
|
||
}
|
||
```
|
||
|
||
## 步骤 7:验证测试仍然通过
|
||
|
||
```bash
|
||
npm test lib/liquidity.test.ts
|
||
|
||
PASS lib/liquidity.test.ts
|
||
✓ should return high score for liquid market (3 ms)
|
||
✓ should return low score for illiquid market (2 ms)
|
||
✓ should handle edge case: zero volume (1 ms)
|
||
|
||
3 tests passed
|
||
```
|
||
|
||
✅ 重构完成,测试仍然通过!
|
||
|
||
## 步骤 8:检查覆盖率
|
||
|
||
```bash
|
||
npm test -- --coverage lib/liquidity.test.ts
|
||
|
||
File | % Stmts | % Branch | % Funcs | % Lines
|
||
---------------|---------|----------|---------|--------
|
||
liquidity.ts | 100 | 100 | 100 | 100
|
||
|
||
Coverage: 100% ✅ (Target: 80%)
|
||
```
|
||
|
||
✅ TDD 会话完成!
|
||
|
||
```
|
||
|
||
## TDD Best Practices
|
||
|
||
**DO:**
|
||
- ✅ Write the test FIRST, before any implementation
|
||
- ✅ Run tests and verify they FAIL before implementing
|
||
- ✅ Write minimal code to make tests pass
|
||
- ✅ Refactor only after tests are green
|
||
- ✅ Add edge cases and error scenarios
|
||
- ✅ Aim for 80%+ coverage (100% for critical code)
|
||
|
||
**DON'T:**
|
||
- ❌ Write implementation before tests
|
||
- ❌ Skip running tests after each change
|
||
- ❌ Write too much code at once
|
||
- ❌ Ignore failing tests
|
||
- ❌ Test implementation details (test behavior)
|
||
- ❌ Mock everything (prefer integration tests)
|
||
|
||
## Test Types to Include
|
||
|
||
**Unit Tests** (Function-level):
|
||
- Happy path scenarios
|
||
- Edge cases (empty, null, max values)
|
||
- Error conditions
|
||
- Boundary values
|
||
|
||
**Integration Tests** (Component-level):
|
||
- API endpoints
|
||
- Database operations
|
||
- External service calls
|
||
- React components with hooks
|
||
|
||
**E2E Tests** (use `/e2e` command):
|
||
- Critical user flows
|
||
- Multi-step processes
|
||
- Full stack integration
|
||
|
||
## Coverage Requirements
|
||
|
||
- **80% minimum** for all code
|
||
- **100% required** for:
|
||
- Financial calculations
|
||
- Authentication logic
|
||
- Security-critical code
|
||
- Core business logic
|
||
|
||
## Important Notes
|
||
|
||
**MANDATORY**: Tests must be written BEFORE implementation. The TDD cycle is:
|
||
|
||
1. **RED** - Write failing test
|
||
2. **GREEN** - Implement to pass
|
||
3. **REFACTOR** - Improve code
|
||
|
||
Never skip the RED phase. Never write code before tests.
|
||
|
||
## Integration with Other Commands
|
||
|
||
- Use `/plan` first to understand what to build
|
||
- Use `/tdd` to implement with tests
|
||
- Use `/build-fix` if build errors occur
|
||
- Use `/code-review` to review implementation
|
||
- Use `/test-coverage` to verify coverage
|
||
|
||
## Related Agents
|
||
|
||
This command invokes the `tdd-guide` agent located at:
|
||
`~/.claude/agents/tdd-guide.md`
|
||
|
||
And can reference the `tdd-workflow` skill at:
|
||
`~/.claude/skills/tdd-workflow/`
|
||
|
||
```
|