Tdd workflow
Skill VersoXBT/claude-initial-setup/skills/testing/tdd-workflow
75 skills, 14 agents, 15 commands for Claude Code. Plug-and-play starter kit covering TypeScript, Python, Go, Rust, React, Next.js, FastAPI, Django, Docker, CI/CD, security, testing, and more. Cross-AI support for Cursor, Copilot, and Codex.
npx -y skills add VersoXBT/claude-initial-setup --skill tdd-workflowAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Red-green-refactor TDD cycle, test-first methodology, coverage targets (80%+), and test pyramid. Use when the user is implementing a new feature, fixing a bug, asks about TDD, or mentions writing tests before code. Always push for test-first.
SKILL.md
6.5 KB, as published. Nobody here has run it
TDD Workflow
Test-Driven Development means writing a failing test before writing implementation code. This ensures every feature has coverage and drives cleaner design through the red-green-refactor cycle.
When to Use
- User is implementing a new feature (push for test-first)
- User is fixing a bug (write a test that reproduces the bug first)
- User asks about TDD or test-driven development
- User asks how to structure tests
- Coverage is below 80% and needs improvement
Core Patterns
The Red-Green-Refactor Cycle
RED: Write a failing test
|
v
GREEN: Write minimal code to pass
|
v
REFACTOR: Clean up without changing behavior
|
v
(repeat)
Step 1: RED — Write a Failing Test
Write the test first. It must fail because the implementation does not exist yet:
// src/utils/slug.test.ts
import { describe, it, expect } from 'vitest'
import { createSlug } from './slug'
describe('createSlug', () => {
it('converts a title to a URL-safe slug', () => {
expect(createSlug('Hello World')).toBe('hello-world')
})
it('removes special characters', () => {
expect(createSlug('Hello & World!')).toBe('hello-world')
})
it('collapses multiple hyphens', () => {
expect(createSlug('Hello World')).toBe('hello-world')
})
it('trims leading and trailing hyphens', () => {
expect(createSlug(' Hello World ')).toBe('hello-world')
})
})
Run the test — it must FAIL:
npx vitest run src/utils/slug.test.ts
# FAIL: Cannot find module './slug'
Step 2: GREEN — Minimal Implementation
Write the minimum code to make all tests pass:
// src/utils/slug.ts
export function createSlug(title: string): string {
return title
.toLowerCase()
.replace(/[^a-z0-9\s-]/g, '')
.replace(/\s+/g, '-')
.replace(/-+/g, '-')
.replace(/^-|-$/g, '')
}
Run the test — it must PASS:
npx vitest run src/utils/slug.test.ts
# PASS: All 4 tests passed
Step 3: REFACTOR — Improve Without Changing Behavior
Clean up the implementation while keeping all tests green:
// src/utils/slug.ts (refactored)
const SPECIAL_CHARS = /[^a-z0-9\s-]/g
const WHITESPACE = /\s+/g
const MULTIPLE_HYPHENS = /-+/g
const EDGE_HYPHENS = /^-|-$/g
export function createSlug(title: string): string {
return title
.toLowerCase()
.replace(SPECIAL_CHARS, '')
.replace(WHITESPACE, '-')
.replace(MULTIPLE_HYPHENS, '-')
.replace(EDGE_HYPHENS, '')
}
Run tests again to confirm nothing broke:
npx vitest run src/utils/slug.test.ts
# PASS: All 4 tests passed
Bug Fix TDD
For bug fixes, write a test that reproduces the bug first:
// 1. Bug report: createSlug crashes on empty string
// 2. RED: Write test that demonstrates the bug
it('handles empty string', () => {
expect(createSlug('')).toBe('')
})
// 3. Run test — confirms the bug exists (FAIL or unexpected behavior)
// 4. GREEN: Fix the implementation
export function createSlug(title: string): string {
if (!title) return ''
// ... rest of implementation
}
// 5. Run test — bug is fixed (PASS)
Test Pyramid
Structure tests by scope and speed:
/ E2E \ Few, slow, high-value
/----------\ (Playwright, Cypress)
/ Integration \ Moderate count, medium speed
/----------------\ (API tests, DB tests)
/ Unit Tests \ Many, fast, focused
/----------------------\ (Vitest, Jest, pytest)
Coverage targets by layer:
| Layer | Target | Speed | Count |
|---|---|---|---|
| Unit | 80%+ line coverage | < 1s each | Many |
| Integration | Key workflows | < 5s each | Moderate |
| E2E | Critical paths | < 30s each | Few |
Coverage Verification
Check coverage after each TDD cycle:
# Vitest
npx vitest run --coverage
# Jest
npx jest --coverage
# pytest
python -m pytest --cov=src --cov-report=term-missing
Target 80% minimum overall. Focus on:
- All public functions/methods
- All error paths
- All edge cases (empty input, null, boundary values)
TDD for API Endpoints
// 1. RED: Write the integration test
describe('POST /api/users', () => {
it('creates a user and returns 201', async () => {
const response = await request(app)
.post('/api/users')
.send({ email: '[email protected]', name: 'Test' })
expect(response.status).toBe(201)
expect(response.body.data.email).toBe('[email protected]')
})
it('returns 400 for invalid email', async () => {
const response = await request(app)
.post('/api/users')
.send({ email: 'not-an-email', name: 'Test' })
expect(response.status).toBe(400)
expect(response.body.error).toContain('email')
})
})
// 2. GREEN: Implement route, validation, and handler
// 3. REFACTOR: Extract validation schema, clean up handler
Anti-Patterns
- Writing tests after implementation: This is "test-after" not TDD. Tests written after code tend to test the implementation rather than the behavior, and they always pass on first run — so you never see RED.
- Skipping the RED step: If your test passes on the first run, either the feature already exists or the test is wrong. A passing new test is suspicious.
- Over-implementing in GREEN: Write the minimum to pass, not the "best" solution. Optimization comes in REFACTOR. Minimal GREEN keeps you honest about what the tests actually require.
- Skipping REFACTOR: Going RED-GREEN-RED-GREEN without refactoring accumulates technical debt. Always clean up after GREEN.
- Testing implementation details: Test behavior (what), not implementation (how).
expect(result).toBe('hello-world')is good.expect(internalRegex).toHaveBeenCalled()is brittle. - Fixing tests to match broken code: If a test fails after a code change, the code is probably wrong, not the test. Fix the implementation first.
Quick Reference
1. RED: Write test -> Run -> Must FAIL
2. GREEN: Write minimal code -> Run -> Must PASS
3. REFACTOR: Clean up -> Run -> Must still PASS
4. COVERAGE: Check -> Must be 80%+
5. REPEAT
Bug fixes: Always reproduce with a test first.
New features: Always write the test before the implementation.
Coverage: 80% minimum. Check with --coverage flag.
Pyramid: Many unit tests, moderate integration, few E2E.