Skip to content

Test and debug with Claude Code

Testing and debugging with Claude Code works when the tests, not the model, decide what “done” means: the test commands live in CLAUDE.md, hooks rerun the suite after every edit, the implementing session cannot edit the test files, and every bug fix starts with a test that fails for the diagnosed reason. Plan mode keeps diagnosis read-only.

This hub is for developers who let Claude Code write tests and fixes, and for tech leads who decide what those pull requests must prove. The familiar failure: Claude reports “all tests pass”, coverage goes up, and the bug ships anyway, because the new tests asserted that mocks were called or an assertion was quietly loosened. Commands were checked against Claude Code v2.1.283 (latest channel).

Which Claude Code test page answers your question?

Section titled “Which Claude Code test page answers your question?”
Your questionPage
How do I get tests that follow our patterns, run red-green-refactor, and catch real bugs?Test generation and TDD with Claude Code
Something is broken. How do I find the root cause instead of patching the symptom?Debugging with Claude Code in the terminal
How strong does a suite have to be before I trust tests I did not read?How strong is your oracle?
How do I stop the agent from editing the checks that judge it?Protecting the oracle
Claude Code itself misbehaves: hangs, permission loops, lost contextTroubleshooting Claude Code

Testing practice that is the same in every agent is in testing workflows for every tool.

In what order should you set up testing with Claude Code?

Section titled “In what order should you set up testing with Claude Code?”

Each step removes one way for a green result to lie. Do them once per repository.

  1. Write the test commands into CLAUDE.md. Name the command for one file, for related tests and for the full suite, plus the rule “never edit a test to make it pass”. Claude uses these instead of guessing.

  2. Add the feedback hooks. A PostToolUse hook on Edit|Write runs the related tests after each edit, and a Stop hook runs the fast suite before Claude reports done. Both exit with code 2 on failure, which sends the hook’s stderr back to Claude, so redirect the runner’s output with 1>&2. The scripts and settings block are in test generation and TDD; other events are in hooks automation.

  3. Lock the tests while Claude implements. “Do not edit the test” in a prompt is a request. A deny rule such as "Edit(**/*.test.ts)" in permissions.deny (or claude --disallowedTools "Edit(**/*.test.ts)") blocks the file tools and recognized shell writes such as sed and >, but not a script that opens files itself. A CI check outside the diff is the lock for the branch.

  4. Diagnose read-only. From v2.1.283 (the latest channel), interactive sessions usually start in auto mode, where a classifier approves actions instead of you; claude -p and some providers’ default models still start in Manual. For a bug, switch to plan mode (claude --permission-mode plan, /plan, or Shift+Tab) so nothing changes until Claude names one cause as file, line and condition.

  5. Prove before fixing. A new test must fail for the diagnosed reason before any fix is written. If it fails for a different reason, the diagnosis is wrong.

How do you know Claude Code’s tests and fixes are right without reading every line?

Section titled “How do you know Claude Code’s tests and fixes are right without reading every line?”

Read the evidence and open the diff only where the evidence points.

EvidenceWhat it provesOwner
A list of test names approved before generationThe suite covers the behaviours you care aboutDeveloper
The new test ran red, for the stated reason, before the fixThe test detects the bug it claims toDeveloper (from hook output)
Test files unchanged in the fix’s diffNobody passed the suite by weakening itCI check on test paths
Mutation survivors listed and triagedThe suite catches injected bugs, not only today’s codeReviewer
Full suite, types and lint green in CIExisting behaviour still holds, outside the agent’s controlCI

What a pull request attaches as proof is defined in the evidence bundle, and why you read evidence instead of the diff is argued in reading evidence instead of code. The fix-by-test habit behind this table is in test-driven fixing.

What goes wrong when Claude Code tests and debugs its own work?

Section titled “What goes wrong when Claude Code tests and debugs its own work?”
SymptomCauseRecovery
Suite green, bug in productionTests assert mocks, not behaviourAdd an integration test at the seam; run the mutation prompt above
A fix passes by changing an assertionTest files were editable during the fixAdd the permissions.deny rule and a CI check that fails when test paths change without an owner’s approval
The same crash returns from another callerClaude patched the symptom with a null checkReturn to plan mode; ask where the bad value is produced and which callers share the assumption
Turns end slowly, or Claude loops on a red suiteThe Stop hook runs a slow or flaky suitePoint it at the fast unit tests; leave slow suites to CI
Snapshot files change in a fix although tests are deniedvitest -u or a script rewrote them; deny rules do not cover subprocesses that open files themselvesRevert the snapshots, add "Bash(npx vitest * -u*)" and "Bash(npx vitest * --update*)" to permissions.deny (other spellings, such as pnpm vitest or npm test -- -u, need their own rules), and make the CI test-path check include __snapshots__/, which is the real lock
The diagnosis sounds right but the new test fails differentlyTwo plausible causes were never separatedTreat the diagnosis as disproved; ask Claude for the evidence that rules each cause out

Where to go next with testing and debugging in Claude Code

Section titled “Where to go next with testing and debugging in Claude Code”

The code under test comes from building with Claude Code. Using another agent as well? The same stage is covered in test and debug with Codex and test and debug with Cursor.