327 lines
8.0 KiB
Markdown
327 lines
8.0 KiB
Markdown
---
|
|
description: Enforce test-driven development workflow. Scaffold interfaces, generate tests FIRST, then implement minimal code to pass. Ensure 80%+ coverage.
|
|
---
|
|
|
|
# TDD Command
|
|
|
|
This command invokes the **tdd-guide** agent to enforce test-driven development methodology.
|
|
|
|
## What This Command Does
|
|
|
|
1. **Scaffold Interfaces** - Define types/interfaces first
|
|
2. **Generate Tests First** - Write failing tests (RED)
|
|
3. **Implement Minimal Code** - Write just enough to pass (GREEN)
|
|
4. **Refactor** - Improve code while keeping tests green (REFACTOR)
|
|
5. **Verify Coverage** - Ensure 80%+ test coverage
|
|
|
|
## When to Use
|
|
|
|
Use `/tdd` when:
|
|
- Implementing new features
|
|
- Adding new functions/components
|
|
- Fixing bugs (write test that reproduces bug first)
|
|
- Refactoring existing code
|
|
- Building critical business logic
|
|
|
|
## How It Works
|
|
|
|
The tdd-guide agent will:
|
|
|
|
1. **Define interfaces** for inputs/outputs
|
|
2. **Write tests that will FAIL** (because code doesn't exist yet)
|
|
3. **Run tests** and verify they fail for the right reason
|
|
4. **Write minimal implementation** to make tests pass
|
|
5. **Run tests** and verify they pass
|
|
6. **Refactor** code while keeping tests green
|
|
7. **Check coverage** and add more tests if below 80%
|
|
|
|
## TDD Cycle
|
|
|
|
```
|
|
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
|
|
```
|
|
|
|
## Example Usage
|
|
|
|
```
|
|
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')
|
|
}
|
|
```
|
|
|
|
## Step 2: Write Failing Test (RED)
|
|
|
|
```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)
|
|
})
|
|
})
|
|
```
|
|
|
|
## Step 3: Run Tests - Verify FAIL
|
|
|
|
```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
|
|
```
|
|
|
|
✅ Tests fail as expected. Ready to implement.
|
|
|
|
## Step 4: Implement Minimal Code (GREEN)
|
|
|
|
```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
|
|
}
|
|
```
|
|
|
|
## Step 5: Run Tests - Verify PASS
|
|
|
|
```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
|
|
```
|
|
|
|
✅ All tests passing!
|
|
|
|
## Step 6: Refactor (IMPROVE)
|
|
|
|
```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)
|
|
}
|
|
```
|
|
|
|
## Step 7: Verify Tests Still Pass
|
|
|
|
```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
|
|
```
|
|
|
|
✅ Refactoring complete, tests still passing!
|
|
|
|
## Step 8: Check Coverage
|
|
|
|
```bash
|
|
npm test -- --coverage lib/liquidity.test.ts
|
|
|
|
File | % Stmts | % Branch | % Funcs | % Lines
|
|
---------------|---------|----------|---------|--------
|
|
liquidity.ts | 100 | 100 | 100 | 100
|
|
|
|
Coverage: 100% ✅ (Target: 80%)
|
|
```
|
|
|
|
✅ TDD session complete!
|
|
```
|
|
|
|
## 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-and-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/`
|