Stacks

Write Unit Tests for Untested Code in Rust with Atlas (2026)

Updated 9 min read

Atlas writes unit tests for an untested Rust module by reading the module, enumerating its exported symbols with the lsp tool's documentSymbol operation so no pub function is missed, and copying the conventions your crate already uses rather than inventing its own. Atlas greps for an existing test to learn whether you keep unit tests in a #[cfg(test)] mod tests block inside the file or as integration tests under tests/, writes the new tests with the write tool, which shows the diff in the permission prompt before anything lands on disk, and then runs cargo test through bash. The run is the point: a test that was never executed is not a test.

How do you add cargo test coverage to an untested Rust module?

Atlas covers an untested Rust module in 5 moves: read the module, enumerate every exported symbol with the lsp tool's documentSymbol operation, grep an existing test for conventions, write the tests, then run cargo test through bash. Step two is what keeps a pub function from being quietly skipped.

Rust modules hide a surprising amount of public surface behind a short file. src/pricing.rs might expose three pub fn items, two pub methods on an impl block, a pub trait with a default method, and a From implementation that everything downstream depends on. A model that skims the file and writes tests for the two functions it noticed produces a confident summary and thin coverage. Atlas enumerates instead. The lsp tool's documentSymbol operation returns the symbol table from the language server, so every pub item in the module appears in the list, including trait impls and associated functions. Atlas then reads the bodies to understand what each one actually does, because a Rust test that only restates the type signature is testing the compiler, which does not need help.

Does Atlas put Rust tests in a #[cfg(test)] module or in tests/?

Atlas greps your crate and copies whatever it finds. Rust supports 2 placements, a #[cfg(test)] mod tests block inside src/pricing.rs and integration tests under tests/, and the choice is not cosmetic: an inline module can reach private items, while a file in tests/ can only touch the public API of the crate.

That distinction is exactly the kind of thing a model gets wrong when it guesses. Write the test in tests/ and it cannot call a private helper, so it fails to compile and the natural repair is to make the helper pub, which quietly widens your crate's public API to satisfy a test. Write it inline when the crate's convention is integration tests and it looks foreign to every reviewer. Atlas resolves the question with evidence. grep for #[cfg(test)] and for files under tests/, read the closest example, and mirror the framework, the import style (a use super::*; at the top of the inline module is the usual idiom), and the naming convention. Atlas indexes code by AST declarations using tree-sitter, so the search returns real declarations rather than arbitrary line windows.

Does Atlas actually run cargo test, or just generate test code?

Atlas runs cargo test itself through the bash tool and reads the failures. Output over 2000 lines or 50 KB is truncated and the complete log is written to a file Atlas can read, so a crate whose tests emit long panic backtraces still gets triaged in full rather than from a tail.

Generated Rust tests that were never compiled are worse than no tests, because they carry the appearance of coverage. The first cargo test run of a freshly written test file in Rust very often fails, and usually not on the assertion: it fails on the borrow checker, on a moved value in the second assert, or on a missing Clone. Those are real design signals about the module under test, and they are only visible because the test was executed. Atlas iterates with the edit tool until cargo test is green, keeping progress in a todowrite list when the module is large enough that a dozen pub items each need their own case. Ask Atlas to fix borrow-checker errors or clippy warnings that surface along the way, and review the diff before cargo build.

How does Atlas decide what to assert in a Rust test?

Atlas asserts on behavior, and in Rust that means the Result and Option branches, not just the happy path. A pub fn returning Result<Invoice, PricingError> has at least 2 behaviors worth pinning, and documentSymbol lists the error enum alongside the function, so both ends of the signature end up covered.

Rust's type system does a great deal of the work that tests do in other languages, which changes what a good Rust test asserts. There is no point testing that a function refuses a wrong type; rustc already guarantees it. What is worth testing is the logic inside the Result: which inputs produce Err, which variant of the error enum, whether an Option is None at the boundary, whether an arithmetic path saturates or wraps as intended. Atlas reads the module body before writing so the assertions target those branches, using assert_eq! for values and matching on the error variant rather than merely checking is_err(). Run rustfmt on the new test file so it matches the rest of the crate, and let cargo test decide whether the assertions hold.

How do I review Rust tests an AI agent wrote before they land?

In 2026, Atlas shows the new test file as a diff in the write tool's permission prompt before anything lands on disk, and every Atlas tool call is permission-gated against allow, ask, and deny rules before it runs. Adding src/pricing.rs tests is therefore an approval you give, not something you discover later in git status.

Reviewing an AI-written Rust test is quick if you know what to look for. Does the test cover the Err branches documentSymbol surfaced, or only the happy path? Does it live in the right place given whether it needs private access? Does it avoid smuggling in an unwrap that turns a real failure into a panic with no message? Does it clone excessively to dodge the borrow checker rather than modeling ownership the way the rest of the crate does? Atlas gives you the diff up front, and it snapshots file changes as git patches, so a test file you decide against can be diffed and rolled back cleanly. When the tests are right, cargo test is the arbiter and rustfmt keeps them consistent with the crate.

Step by step

  1. 01Start atlas in the crate that holds Cargo.toml so the index covers your modules, traits, and the rest of the cargo workspace.
  2. 02Have Atlas read the untested module, for example src/pricing.rs, so the tests assert on real behavior rather than restating type signatures.
  3. 03Use the lsp tool's documentSymbol operation to enumerate the module's exported symbols, including pub methods on impl blocks and trait implementations, so no public item is missed.
  4. 04Grep for an existing #[cfg(test)] mod tests block and for files under tests/ to learn whether the crate keeps unit tests inline or as integration tests.
  5. 05Let Atlas write the tests with the write tool, matching the crate's import idiom such as use super::*;, and read the diff in the permission prompt before it lands.
  6. 06Run cargo test with the bash tool; output over 2000 lines or 50 KB is truncated and the full log is saved to a file Atlas can read.
  7. 07Iterate with the edit tool until cargo test is green, asking Atlas to work through borrow-checker errors or clippy warnings that the new tests surface.
  8. 08Run rustfmt on the new test code, keep one todowrite entry per untested pub item when the module is large, and review the diff before cargo build.

Frequently asked questions

Can an AI agent write cargo test coverage for a Rust module that has none?
Yes. Atlas reads the module, enumerates its exported symbols with the lsp tool's documentSymbol operation, greps the crate for existing test conventions, writes the tests with the write tool, and runs cargo test through bash until the crate is green.
Should Rust unit tests go in a #[cfg(test)] module or the tests directory?
It depends on access, and Atlas greps your crate to find out what you already do. An inline #[cfg(test)] mod tests block can reach private items; a file under tests/ only sees the crate's public API, so putting the wrong test there pressures you to widen visibility.
How do I make sure every pub function in my Rust module gets tested?
Use the symbol table. Atlas calls the lsp tool's documentSymbol operation to enumerate exported symbols, so pub functions, pub methods on impl blocks, and trait implementations in src/pricing.rs all appear rather than only the ones a skim would notice.
Does Atlas run the Rust tests it writes?
Yes. Atlas runs cargo test with the bash tool and reads the failures, iterating with edit until the suite passes. Output over 2000 lines or 50 KB is truncated and the complete log is saved to a file, so long panic backtraces are still triaged in full.
What should a Rust unit test actually assert?
Behavior, not types. rustc already rejects wrong types, so the value is in pinning the Err variants of a Result, the None branches of an Option, and arithmetic edge cases, matching on the error variant rather than only checking is_err().
Will the new tests break on the borrow checker?
Often, and that is useful information. The first cargo test run of new Rust tests commonly fails on a moved value or a missing Clone. Ask Atlas to fix borrow-checker errors or clippy warnings, then review the diff before cargo build.
How do I review Rust test files an AI agent generated before they land?
The write tool shows the file as a diff in the permission prompt before anything lands on disk, and every Atlas tool call is permission-gated against allow, ask, and deny rules. Atlas also snapshots changes as git patches, so a rejected test file rolls back cleanly.

Try Atlas in your terminal

The terminal-native AI coding agent. Free core, single binary.

Install Atlas

Related guides

Write Unit Tests for Untested Code with Atlas in 2026

How to write unit tests for untested code with Atlas in 2026: the lsp tool enumerates exported symbols, grep copies repo conventions, and bash actually runs the suite.

Atlas for Rust in 2026

Adopt Atlas, the terminal-native AI coding agent, for Rust development in 2026. Tackle borrow checker errors and clippy lints with Atlas's secure, approval-gated assistance.

Automate GitHub Issue and Pull Request Triage in Rust with Atlas in 2026

In 2026, Rust developers can automate GitHub issue and pull request triage using Atlas, ensuring safe, permission-gated responses within their cargo projects. Leverage Atlas's AI to manage your Rust codebase efficiently.

Plan a Multi-File Change Before Editing in Rust with Atlas (2026)

Design a Rust refactor across crates with the Atlas plan agent, which blocks every edit tool until you approve. Then let cargo test, cargo, and rustfmt confirm it.

Refactor a legacy module in Rust with Atlas (2026)

Refactor a legacy Rust module in 2026 with Atlas: enumerate callers with the lsp tool's findReferences, restructure with apply_patch, and prove behavior with cargo test.

Trace a Runtime Bug From a Stack Trace in Rust with Atlas (2026)

Go from a Rust panic backtrace to the responsible line without a debugger. Atlas reads each frame at its offset in 2026, then proves the fix with cargo test.

Extract a Shared Helper from Duplicated Rust Code with Atlas (2026)

Extract a shared helper from duplicated Rust code with Atlas in 2026. Find near-duplicates with codebase_search, add a module, swap each copy with apply_patch, run cargo test.

Locate Where a Behavior Is Implemented in Rust with Atlas in 2026

Find the exact Rust file, trait, and impl behind a behavior in 2026. Atlas pairs codebase_search with grep through ripgrep and the lsp tool's findReferences.

Browse this resource hub