Claude Code Testing: TDD, Test Generation & Debugging with AI
Testing is where Claude Code truly shines. It can write tests, run them, see failures, fix the code, and re-run -- all in a single loop. Whether you practice strict TDD or just want better test coverage, Claude Code transforms testing from a chore into a conversation.
Test-Driven Development with Claude Code
TDD with Claude Code follows the classic red-green-refactor cycle, but faster because Claude handles the typing:
1. Write the test first
> Write a failing test for a calculateDiscount function that takes a price and
a discount percentage, handles edge cases (negative values, over 100%),
and returns the discounted price rounded to 2 decimal places.
Claude will create a test file with comprehensive test cases including happy paths, edge cases, and error handling.
2. Run the test (it fails)
> Run the test
Claude executes the test, sees it fail (because the function doesn't exist yet), and shows you the output.
3. Implement to make it pass
> Now implement calculateDiscount to make all tests pass
Claude writes the implementation, runs the tests again, and iterates until everything is green.
4. Refactor
> Refactor the implementation for clarity. Keep all tests passing.
Pro tip: Set up a Stop hook that runs your test suite after every Claude turn. This creates an automatic TDD loop where Claude writes code, tests run, and failures feed back for immediate fixing.
Generating Tests for Existing Code
The most common testing task is adding tests to code that already exists. Claude Code excels at this because it can read your source code, understand the behavior, and generate meaningful tests.
Test a single file
> Write comprehensive tests for src/utils/validation.ts.
Cover all exported functions, edge cases, and error conditions.
Use the testing conventions from the rest of the project.
Test an entire module
> Add test coverage for the entire src/api/ directory.
Look at existing tests for style conventions.
Run each test file as you create it to make sure they pass.
Test from a spec or description
> Here's the product spec for the shopping cart:
- Users can add/remove items
- Quantity updates recalculate totals
- Discount codes apply percentage or fixed amount off
- Tax is calculated based on shipping state
- Free shipping over $50
Write tests that verify all of these behaviors against our CartService class.
Improving Test Coverage
Claude Code can analyze your coverage reports and surgically add tests where they're needed:
> Run the test suite with coverage. Show me the coverage report,
then write tests for the files with the lowest coverage.
Or be more targeted:
> Run coverage for src/services/payment.ts specifically.
Add tests to cover any uncovered branches or lines.
The coverage improvement loop
For a systematic approach, use this iterative pattern:
> Run coverage. Find the 5 files with the lowest coverage percentages.
For each one, add tests to bring coverage above 80%.
Run coverage again after each file to verify improvement.
Claude Code will work through each file methodically, checking coverage as it goes.
Debugging Failing Tests
When tests fail, Claude Code is your debugging partner. Instead of staring at stack traces, describe the situation:
Fix a specific failure
> The UserService.create test is failing with "unique constraint violation".
Figure out why and fix it.
Claude will read the test, the service code, understand the database constraints, and fix the issue -- whether it's in the test setup, the implementation, or both.
Fix flaky tests
> The integration tests in tests/api/ are flaky -- they pass locally
but fail intermittently in CI. Investigate and fix the root cause.
Common causes Claude can identify and fix: race conditions, shared test state, missing cleanup, port conflicts, and timing-dependent assertions.
Diagnose test suite issues
> Our test suite takes 4 minutes to run. Analyze it and suggest
optimizations. Look for slow tests, unnecessary setup, and
opportunities to parallelize.
Testing Patterns by Framework
React with Testing Library
> Write tests for the SearchBar component. Test:
- Rendering with default props
- User typing triggers debounced search
- Loading state shows spinner
- Results display correctly
- Empty state message
Use React Testing Library and follow the existing test patterns in the project.
API endpoints with supertest
> Write integration tests for the /api/orders endpoints.
Test all CRUD operations, authentication requirements,
validation errors, and pagination. Use supertest.
Database operations
> Write tests for the OrderRepository class. Use a test database
with proper setup/teardown. Test all queries including edge cases
like empty results and concurrent updates.
Automated Testing with Stop Hooks
The most powerful testing pattern with Claude Code is using hooks to create an automatic feedback loop. Add this to your .claude/settings.json:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hook": "npm test -- --bail --watchAll=false 2>&1 | tail -30"
}
]
}
}
Now every time Claude writes or edits a file, the test suite runs automatically. If tests fail, Claude sees the output and can fix the issue immediately. This creates a true TDD feedback loop without you having to say "run the tests" after every change.
Stop hook for continuous testing
{
"hooks": {
"Stop": [
{
"hook": "npm test -- --bail 2>&1 | tail -30"
}
]
}
}
This runs your entire test suite every time Claude finishes a turn. If anything fails, Claude gets another turn to fix it -- creating a self-correcting development loop.
CI/CD Integration
Claude Code can help set up and maintain your CI testing pipeline:
Generate CI configuration
> Create a GitHub Actions workflow that runs our test suite on every PR.
Include: lint, type check, unit tests, integration tests (with a test database),
and coverage reporting. Cache node_modules between runs.
Fix CI failures
> The CI is failing on this PR. Here's the error output:
[paste CI log]
Fix the issue.
Headless test generation
Use Claude Code in headless mode to generate tests as part of your CI pipeline:
# In your CI script
claude -p "Check test coverage. If any file in src/ has below 70% coverage, write tests to improve it. Run the full suite to verify."
Testing Best Practices with Claude Code
- Specify your testing framework in CLAUDE.md: "Use Vitest for unit tests and Playwright for E2E tests" prevents Claude from guessing
- Point to existing tests as examples: "Follow the same patterns as tests/services/auth.test.ts" gives Claude a style template
- Ask for edge cases explicitly: "Include tests for null inputs, empty strings, very large numbers, and concurrent access"
- Run tests incrementally: "Write tests for each function, running them as you go" catches issues early
- Review generated tests: AI-generated tests can have blind spots -- make sure they test behavior, not implementation details
- Use meaningful test names: Tell Claude "Use descriptive test names that explain the expected behavior" to avoid names like
test1
CLAUDE.md Testing Section
Add a testing section to your CLAUDE.md for consistent test generation:
## Testing
### Frameworks
- Unit tests: Vitest
- Component tests: React Testing Library + Vitest
- E2E tests: Playwright
- API tests: supertest
### Conventions
- Co-locate unit tests (Button.test.tsx next to Button.tsx)
- E2E tests go in tests/e2e/
- Use factories for test data (see tests/factories/)
- Mock external APIs with msw (see tests/mocks/)
- Each test file should be runnable independently
### Commands
- `npm test` -- run all unit tests
- `npm run test:e2e` -- run Playwright tests
- `npm run test:coverage` -- generate coverage report
- `npm run test:watch` -- run tests in watch mode
Key takeaway: Claude Code's ability to write, run, and iterate on tests in a single loop makes it one of the most effective test-writing tools available. Combine it with Stop hooks for a fully automated TDD workflow.