Claude Code is well-suited for test-driven development (TDD). The key is knowing when to write tests first vs. when to generate code first. Here's how I use it for TDD.
The Core TDD Loop with Claude Code
Classic TDD: write a failing test → write the minimum code to pass → refactor.
With Claude Code, each phase looks like this:
Phase 1 — Write the test:
Write a test for a UserService.createUser() function.
Requirements:
- Takes email (string) and name (string)
- Returns the created user with an id field
- Throws ValidationError if email is invalid
- Throws DuplicateError if email already exists
- Does NOT test the database directly (use mocks)
Don't write the implementation yet.
Phase 2 — Write the implementation:
The test is now written. Write the UserService.createUser()
implementation that makes all tests pass.
Here's the test: [paste the test]
Phase 3 — Refactor:
The tests are passing. Refactor the implementation for
readability without changing behavior.
Why "Write Tests First" Works Better Than "Generate Both"
Asking Claude Code to "write UserService with tests" in one shot often produces:
- Tests that are written to match the implementation (not requirements)
- Missing edge cases
- Tests that pass because they test the wrong thing
Writing requirements → test → implementation forces:
- Thinking through requirements before coding
- Test cases that reflect actual expected behavior
- Implementation that's shaped by testability
CLAUDE.md for TDD Projects
## Testing Rules
- Tests are written BEFORE implementations
- Test files are in `tests/` matching `src/` structure
- Test naming: describe("UserService", () => { describe("createUser", () => {
- Pattern: Arrange, Act, Assert (one assertion per it() block)
- External services are always mocked (no real API calls in tests)
- Database is mocked with vitest-mock-extended / pytest-mock
- Test data: use factories in `tests/factories/`, not raw objects
## TDD Workflow
1. Write failing test
2. Write minimum implementation to pass
3. Refactor (with tests still passing)
4. Run: npm test (must be 100% green before any PR)
Generating Test Factories
Write a factory for the User model for use in tests.
Requirements:
- Default values for all required fields
- Override any field with an options object
- Returns typed User objects
User model:
[paste the type/model definition]
Result:
// tests/factories/user.factory.ts
import type { User } from '@/types';
let counter = 0;
export function createUser(overrides: Partial<User> = {}): User {
counter++;
return {
id: `user-${counter}`,
email: `user${counter}@example.com`,
name: `Test User ${counter}`,
createdAt: new Date('2026-01-01'),
...overrides,
};
}
Generating Tests from Specifications
When you have a spec doc or user story, use it directly:
Here's the spec for the payment processing feature:
[paste the spec]
Write all tests that verify this spec. Focus on:
1. Happy path
2. Each error case mentioned in the spec
3. Edge cases not mentioned but implied by business rules
Getting Better Test Coverage
For existing code without tests:
Analyze this function and generate tests that cover:
1. Normal inputs and expected outputs
2. Edge cases (null, empty, boundary values)
3. Error cases
Function: [paste the function]
Then run coverage:
npm test -- --coverage
Current coverage is 72%. The uncovered branches are:
[paste the coverage report]
Write tests to cover these branches.
/test-gen Skill Workflow
With the /test-gen custom skill:
/test-gen src/services/user.service.ts
This generates a test file at tests/services/user.service.test.ts with:
- Import setup
- Mock setup for dependencies
- Test cases for each public method
- Edge cases based on the implementation
Then you review, adjust requirements in the test, and run:
npm test tests/services/user.service.test.ts
CI Integration
Add this to your GitHub Actions workflow so TDD is enforced:
- name: Run tests with coverage
run: npm test -- --coverage --reporter=verbose
- name: Check coverage threshold
run: npx vitest run --coverage.threshold.lines=80
If coverage drops below 80%, the PR is blocked.
/test-gen skill is included in Code Review Pack (¥980) on PromptWorks.
Myouga (@myougatheaxo) — Security-focused Claude Code engineer.
Top comments (0)