# Write Unit Tests for Untested Java Code with Atlas (2026)

> Atlas enumerates a Java class's public methods with documentSymbol, copies the import style already used under src/test/java, then runs JUnit 5 via mvn test.

Writing unit tests for untested Java code starts with knowing the full public surface of the class, and Atlas enumerates that surface with the lsp tool's documentSymbol operation instead of skimming the file. Atlas then copies the repo's existing test conventions rather than inventing its own: the framework, the import style, and the naming convention already used under src/test/java. The new class is written with the write tool, placed in the mirrored package, and then executed. Atlas runs JUnit 5 via mvn test with its bash tool, because the run is the point: a test that was never executed is not a test.

## Key takeaways

- The lsp tool's documentSymbol operation enumerates a Java class's exported symbols, turning the public surface into a checklist instead of an impression.
- Atlas copies the repo's existing test conventions from src/test/java rather than inventing its own import style or naming.
- New test classes go in the mirrored package under src/test/java, which keeps package-private helpers reachable without reflection.
- Atlas runs JUnit 5 via mvn test with the bash tool: a test that was never executed is not a test.
- bash output over 2000 lines or 50 KB is truncated and the full Maven log is saved to a file you can read.
- A todowrite list seeded from the enumerated methods stops a large Java testing pass from stalling on the happy path.

## How do I know which methods of a Java class need unit tests?

Enumerate them, do not skim. Atlas uses the lsp tool's documentSymbol operation to list a Java class's exported symbols, so no public method is missed. A class with 3 declared public methods, 2 package-private helpers, and an inherited method from an abstract base has a wider surface than a quick scroll suggests.

Coverage decisions collapse when the surface is guessed. Java classes inherit, overload, and expose more than the eye catches: two overloads of the same method name are two behaviors, and an @Override of a base class method is a third. documentSymbol enumerates the declarations, turning the class into a checklist of public methods rather than an impression of one. Atlas indexes code by AST declarations using tree-sitter, not blind line windows, so each method declaration in src/main/java is a real unit in the index rather than an arbitrary slice of a 400-line file.

## How does Atlas match my project's existing JUnit import style?

Atlas greps an existing test file under src/test/java to copy the repo's framework, import style, and naming convention. One project imports org.junit.jupiter.api.Test from JUnit 5 and calls assertEquals directly. Another routes every case through a shared fixture base class. Both are valid Java, and only the one your repo already uses will survive review.

Generated tests get rejected on style before anyone reads the assertions. Copying conventions is therefore not politeness, it is the difference between a merged pull request and a rewrite. Look for what the existing suite does about setup: does it use @BeforeEach, a builder, or a static fixture. Look at the naming: shouldReturnEmptyWhenInputIsNull reads differently from testGetItems, and mixing the two in one Maven module is noise. The pom.xml settles the framework question, since Maven resolves the JUnit 5 dependency that every test class in the module must import against.

## Where should a new Java test class live?

A new Java test class belongs in the mirrored package under src/test/java. Maven's standard layout pairs 2 trees, src/main/java and src/test/java, so a class in the com.example.billing package gets its test in the identical package path on the test side, which is what lets the test reach package-private helpers without reflection.

Package mirroring is a Java convention with a practical payoff. A test class in the same package as its subject can exercise package-private methods directly, which frequently removes the temptation to widen a method to public purely for testability. Atlas places the new class accordingly and writes it with the write tool, which shows the diff in the permission prompt before anything lands on disk. Read the generated assertions before approving, particularly the null and exception cases, because a generated test can encode current behavior rather than intended behavior, and a wrong test that passes is worse than no test at all.

## Does Atlas actually run the Java tests it writes?

Yes, and the run is the point. Atlas executes JUnit 5 via mvn test through its bash tool. Output over 2000 lines or 50 KB is truncated and the full log is saved to a file you can read, which matters because Maven prints a surefire report and a stack trace for every failing case in a multi-module build.

A test that was never executed is not a test, it is a guess formatted like one. Running the suite immediately catches the classic generated-test failures: a mocked collaborator that is never injected, an import that Maven cannot resolve, an assertion comparing a String to an Integer. Compilation errors in src/test/java surface first and cascade, so read the saved Maven log from the top rather than the tail. Then iterate with the edit tool until the suite is green, adding one test method at a time so a break is always attributable to the method you just added.

## How do I test a large Java class without losing track?

Keep progress in a todowrite list when the module is large. Seed the list from the documentSymbol enumeration, one pending entry per public method, so a Java class with 8 public methods produces 8 entries and a session that covers the happy path does not silently skip the exception branches.

Testing passes tend to stall at the interesting part. The constructor and the obvious getter get covered, then attention drifts, and the class ends up with coverage that looks respectable while every error branch remains unexercised. A todowrite list built from the enumerated symbols makes the remaining work visible and specific. Work through it method by method, running JUnit 5 via mvn test after each addition. When the suite is green, run Spotless so the new test class matches the project's formatting, and every Atlas tool call along the way is permission-gated against allow, ask, and deny rules before it runs.

## Steps

1. Run atlas in a project with a pom.xml or build.gradle so the Java packages, classpath, and build configuration are in scope.
2. Read the untested class in src/main/java, then use the lsp tool's documentSymbol operation to enumerate its exported symbols so no public method or overload is missed.
3. Grep an existing test file under src/test/java to copy the repo's framework, import style, and naming convention, including whether it uses @BeforeEach or a shared fixture base class.
4. Write the new test class with the write tool, which shows the diff in the permission prompt before anything lands on disk, placing it in the mirrored package so package-private helpers stay reachable.
5. Run the suite with the bash tool by invoking JUnit 5 via mvn test; output over 2000 lines or 50 KB is truncated and the full log is saved to a file you can read.
6. Read the saved Maven log from the top, since a compilation error in src/test/java cascades into everything after it, then iterate with the edit tool until the suite is green.
7. Seed a todowrite list from the documentSymbol enumeration, one pending entry per public method, so the exception branches are not skipped.
8. Run Spotless so the new test class matches the project's formatting before you open the pull request.

## FAQ

### how to add junit 5 tests to a java class with no tests

Have Atlas read the class, enumerate its public methods with the lsp tool's documentSymbol operation, grep an existing test under src/test/java for the import style, then write the class and run JUnit 5 via mvn test.

### will an ai agent write java tests that match my project conventions

Atlas greps an existing test file to copy the repo's framework, import style, and naming convention rather than inventing its own, so the generated class looks like the ones already in src/test/java.

### where should java unit tests be placed in a maven project

In the mirrored package under src/test/java. Maven's standard layout pairs it with src/main/java, and the matching package lets a test exercise package-private helpers directly.

### how do i make sure no public method goes untested in java

Use the lsp tool's documentSymbol operation to enumerate the class's exported symbols, including overloads, then seed a todowrite list with one pending entry per public method.

### maven surefire output too long to read

Atlas's bash tool truncates output over 2000 lines or 50 KB and saves the full log to a file you can read. Read it from the top, because a compilation error in src/test/java cascades.

### can i review a generated java test before it is written to disk

Yes. The write tool shows the diff in the permission prompt before anything lands on disk, and every Atlas tool call is permission-gated against allow, ask, and deny rules before it runs.

### how do i format a generated java test class

Run Spotless, which Maven resolves from your pom.xml. Formatting before the pull request keeps review focused on the assertions rather than on whitespace.

---

Canonical HTML: https://runatlas.sh/resources/stacks/write-unit-tests-for-untested-code-in-java
Source of truth: aeo_pages row `/resources/stacks/write-unit-tests-for-untested-code-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.
