# Debug a Single Failing Test in Java with Atlas (2026)

> Atlas runs one failing JUnit 5 test in isolation via mvn test, walks the Java call path with the lsp tool, and fixes the production code rather than loosening the assertion.

Atlas debugs a single failing Java test by running just that test with the bash tool, using Maven's own filter flag so the output is small enough to reason about, reading the test and the module it exercises, walking the call path with the lsp tool's goToDefinition and findReferences operations, forming a hypothesis, and only then editing. Because the Atlas bash tool is a real shell, every debugging lever you would use by hand in a Java project, extra logging, a focused test filter, a verbose flag, is available. The goal is to fix the code, not the assertion.

## Key takeaways

- Running one JUnit 5 test with Maven's filter flag keeps the output small enough to reason about.
- lsp goToDefinition and findReferences walk the Java call path so the real bug, not the first frame, is found.
- apply_patch replaces chained edits when a Java fix spans several hunks in the same class.
- The final step removes temporary logging, so the reviewed diff contains the fix and nothing else.
- Fix the Java production code, not the assertion, and prove it with the single test plus the full mvn test suite.

## How does Atlas debug one failing JUnit 5 test without running the whole Maven build?

Atlas runs just the failing Java test through the bash tool with Maven's filter flag, for example mvn test -Dtest=OrderServiceTest#appliesBulkDiscount. A single JUnit 5 test produces output small enough to reason about, while a full reactor build across 40 modules buries the assertion in thousands of lines.

Isolation is the first move for a reason. A full JUnit 5 via mvn test run tells you 47 things are red and gives you no room to think about any one of them. Filtering to the single failing test gives you the assertion message, the stack trace, and nothing else. Atlas reads that, then reads the test method itself in src/test/java and the production class it exercises in src/main/java. Only after both are in context does Atlas start forming a hypothesis about which one is wrong.

## How does Atlas walk the Java call path from a failing assertion?

Atlas walks the Java call path with the lsp tool's 2 core operations, goToDefinition and findReferences. From the failing assertion in OrderServiceTest, goToDefinition jumps to the method under test, and findReferences shows every other caller that reaches it, which is how you tell a genuine bug from a test-only misuse.

A failing JUnit 5 assertion names a method, but the bug is rarely in the first method you land on. It is two levels down, in a helper that a Spring-injected collaborator calls with an argument the test did not anticipate. goToDefinition follows the chain through the Java language server, so each hop is real rather than guessed. findReferences answers the other question: if 12 production callsites reach this method and only the test fails, the test may be the thing that is wrong. If the test is the only caller of a code path, the code path is suspect.

## How do you add temporary logging to a Java class while debugging with Atlas?

Atlas forms a hypothesis and checks it at step 3 of the workflow: temporary logging added with the edit tool, or a re-run with a verbose flag through bash. Because bash is a real shell, mvn test -Dtest=OrderServiceTest runs the JUnit 5 test exactly as it would if you typed the command yourself.

Printf debugging remains the fastest way to see what a Java method actually received, and Atlas uses it deliberately rather than reflexively. The edit inserts the logging line, the filtered mvn test run prints it, and the hypothesis is confirmed or dropped. The important discipline is the cleanup: the documented final step removes any temporary logging you added, so the diff that reaches review contains the fix and nothing else. Atlas computes a unified diff for every file edit and surfaces it for approval before writing, which makes the stray log line visible if it survives.

## When should Atlas use apply_patch instead of edit on a Java file?

Atlas fixes the Java production code with the edit tool, but when the change spans several hunks across a class, apply_patch replaces a chain of brittle edits. apply_patch anchors on context lines, so a multi-hunk fix to OrderService.java lands as one reviewable patch rather than 5 independent rewrites.

Chained edits go wrong in a predictable way: the second edit's oldString was computed against the file as it looked before the first edit landed, and the match drifts. apply_patch avoids that by carrying the surrounding context for every hunk and applying them together. For a Java fix that touches a guard clause, a computation, and a return type annotation in the same class, that is the safer tool. The unified diff is still surfaced for approval, so the multi-hunk change is reviewed as a single unit before it is written.

## Why does Atlas fix the Java code instead of loosening the assertion?

The job is to find why one specific Java test fails and fix the code, not the assertion. Atlas re-runs the single JUnit 5 test, then the full mvn test suite, so a fix that satisfies OrderServiceTest by weakening it would be visible as a diff to the test rather than to the production class.

Loosening an assertion is the easiest way to make a Java build green and the fastest way to ship a bug. Atlas separates the two possible verdicts explicitly: either the production code in src/main/java is wrong, in which case the fix goes there, or the test's expectation was wrong, in which case changing the test is correct and the diff should say so out loud. Every edit is surfaced as a unified diff for approval, so which of those two happened is never ambiguous to a reviewer.

## How do you confirm a Java fix did not break anything else?

Atlas re-runs the single failing test first, then the full JUnit 5 via mvn test suite. A targeted mvn test -Dtest run proves the specific bug is gone; the full Maven reactor build proves the fix did not break the other 46 tests that were passing before.

The two runs are not interchangeable. A Java fix to a shared service class routinely satisfies the test you were chasing while violating an invariant three modules away, and only the full suite catches that. When the full run is long, the Atlas bash tool truncates inline output at 2000 lines or 50 KB and writes the complete log to a file you can read. Spotless keeps the touched Java files formatted, and Atlas snapshots file changes as git patches so the fix can be rolled back.

## Steps

1. Run atlas in a project with a pom.xml or build.gradle and let Atlas read your packages, classpath, and build configuration.
2. Run just the failing test with bash using Maven's filter flag, for example mvn test -Dtest=OrderServiceTest#appliesBulkDiscount, so the output is small enough to reason about.
3. Read the JUnit 5 test in src/test/java and the production class it exercises in src/main/java.
4. Use the lsp tool's goToDefinition and findReferences operations to walk the Java call path from the assertion to the real implementation.
5. Form a hypothesis and check it: add temporary logging with edit, or re-run the filtered mvn test through bash with a verbose flag.
6. Fix the production code with edit; if the change spans several hunks in one Java class, use apply_patch instead of chaining brittle edits.
7. Re-run the single JUnit 5 test, then the full mvn test suite, and remove any temporary logging you added.
8. Run Spotless over the touched Java files and review the unified diff Atlas surfaces before approving the write.

## FAQ

### how to debug a single failing JUnit test with an AI agent

Run just that test through the Atlas bash tool with Maven's filter flag so the output is small. Read the test and the class it exercises, walk the call path with the lsp tool's goToDefinition and findReferences, then fix the production code with edit.

### how do I stop an AI agent from just changing the assertion to make a Java test pass

The job is to fix the code, not the assertion. Atlas surfaces a unified diff for every edit, so a change to src/test/java rather than src/main/java is immediately visible to a reviewer. The full mvn test suite then confirms nothing else broke.

### can Atlas add temporary logging to a Java class while debugging

Yes. Atlas adds logging with the edit tool and re-runs the filtered mvn test through bash, which is a real shell. The documented final step removes any temporary logging, so the reviewed diff contains only the fix.

### when should I use apply_patch instead of edit in Java

When the fix spans several hunks in one class. Chained edits drift because each oldString was computed against an older version of the file. apply_patch anchors on context lines and lands the multi-hunk change as one reviewable patch.

### does Atlas work with Maven and JUnit 5

Yes. Start atlas in a project with a pom.xml or build.gradle and it reads your packages, classpath, and build configuration. It runs JUnit 5 via mvn test through the bash tool, using the framework's filter flag to isolate a single test.

### how does Atlas know whether the Java test or the code is wrong

The lsp tool's findReferences operation shows every caller of the method under test. If 12 production callsites reach it and only the test fails, the test's expectation is suspect. If the test is the only caller, the code path itself is suspect.

### does Atlas run Spotless after fixing a Java test

Atlas can run Spotless over the touched Java files through the bash tool, subject to your allow, ask, and deny permission rules. It also snapshots file changes as git patches so a fix can be diffed and rolled back.

---

Canonical HTML: https://runatlas.sh/resources/stacks/debug-a-failing-test-in-java
Source of truth: aeo_pages row `/resources/stacks/debug-a-failing-test-in-java` (segment: Stacks) (this file is generated from it, never hand-edited).
Licence: Atlas is proprietary with a free core. It is not open source and there is no public source repository.
