TDD 命令¶
此命令调用 tdd-guide 代理,以强制执行测试驱动开发(TDD)方法论。
此命令的功能¶
- 构建接口:先定义类型/接口
- 测试先行:编写失败测试(RED)
- 实现最小代码:仅编写足以通过测试的代码(GREEN)
- 重构:在保持测试通过的同时改进代码(REFACTOR)
- 验证覆盖率:确保测试覆盖率不低于 80%
何时使用¶
在以下情况使用 /tdd:
- 实现新功能
- 添加新函数/组件
- 修复 Bug(先编写能复现该 Bug 的测试)
- 重构现有代码
- 构建关键业务逻辑
工作原理¶
tdd-guide 代理将执行以下操作:
- 定义接口:明确输入/输出
- 编写会失败的测试(因为代码尚不存在)
- 运行测试:确认失败原因是否正确
- 编写最小实现:让测试通过
- 运行测试:确认全部通过
- 重构代码:保持测试通过
- 检查覆盖率:若低于 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
使用示例¶
Usuário: /tdd Preciso de uma função para calcular a pontuação de liquidez do mercado
Agent (tdd-guide):
# Sessão TDD: Calculadora de Pontuação de Liquidez de Mercado
第 1 步:定义接口(SCAFFOLD)¶
// 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 步:编写失败测试(RED)¶
// 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 步:运行测试 - 验证失败¶
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 步:实现最小代码(GREEN)¶
// 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 步:运行测试 - 验证通过¶
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 步:重构(IMPROVE)¶
// lib/liquidity.ts - Refatorado com constantes e melhor legibilidade.
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 步:确认测试仍然通过¶
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 个测试通过
通过:重构完成,测试仍然通过!
## 第 8 步:检查覆盖率 {#etapa-8-verificar-a-cobertura}
```bash
npm test -- --coverage lib/liquidity.test.ts
File | % Stmts | % Branch | % Funcs | % Lines
---------------|---------|----------|---------|--------
liquidity.ts | 100 | 100 | 100 | 100
Coverage: 100% PASS: (Target: 80%)
通过:TDD 会话完成! ```
TDD 最佳实践¶
要做的: - 通过:首先编写测试,然后再实现 - 通过:在实现之前运行测试,并确认它们失败 - 通过:编写最小代码以通过测试 - 通过:仅在测试变绿后再重构 - 通过:添加边界情况和错误场景 - 通过:目标覆盖率为 80% 以上(关键代码为 100%)
不要做的: - 失败:在测试之前编写实现 - 失败:每次更改后跳过运行测试 - 失败:一次编写过多代码 - 失败:忽略失败的测试 - 失败:测试实现细节(应测试行为) - 失败:对一切都进行 mock(优先使用集成测试)
应包含的测试类型¶
单元测试(函数级别): - 正常路径场景 - 边界情况(空值、null、最大值) - 错误条件 - 边界值
集成测试(组件级别): - API 端点 - 数据库操作 - 外部服务调用 - 带 hooks 的 React 组件
E2E 测试(使用命令 /e2e):
- 关键用户流程
- 多步骤流程
- 全栈集成
覆盖率要求¶
- 最低 80% 适用于所有代码
- 必须 100% 适用于:
- 金融计算
- 认证逻辑
- 关键安全代码
- 核心业务逻辑
重要说明¶
强制要求:测试必须在实现之前编写。TDD 循环为:
- RED - 编写失败的测试
- GREEN - 实现以通过
- REFACTOR - 改进代码
永远不要跳过 RED 阶段。永远不要在测试之前编写代码。
与其他命令集成¶
- 首先使用
/plan了解要构建什么 - 使用
/tdd进行测试驱动实现 - 如果发生构建错误,使用
/build-fix - 使用
/code-review审查实现 - 使用
/test-coverage检查覆盖率
相关代理¶
此命令调用由 ECC 提供的 tdd-guide 代理。
相关的 tdd-workflow 技能也随 ECC 一起分发。
对于手动安装,源文件位于:
- agents/tdd-guide.md
- skills/tdd-workflow/SKILL.md
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 ev/ECC