# Write unit tests for untested code in C++ with Atlas (2026)

> Atlas writes C++ unit tests by copying the repo's existing GoogleTest conventions, then actually runs them with ctest, because a test that was never executed is not a test.

To add unit tests to an untested C++ module with Atlas, you start from the module's real surface, not from a guess. Atlas reads the target header and translation unit, uses the lsp tool's documentSymbol operation to enumerate every exported symbol so no public function is missed, and greps an existing test file to copy the repo's framework, include style, and TEST_F naming convention rather than inventing its own. Atlas then writes the new spec with the write tool, which shows the diff in the permission prompt before anything lands in tests/. The run is the point: Atlas executes GoogleTest via ctest through the bash tool and reads the failures, because a test that was never executed is not a test. vcpkg supplies the dependencies and clang-format keeps the new file consistent with the rest of the tree.

## Key takeaways

- The lsp tool's documentSymbol operation enumerates every exported C++ symbol, so no public function is left without a GoogleTest case.
- Atlas greps an existing test file to copy the repo's TEST_F conventions and CMake target registration instead of inventing a second dialect.
- The write tool shows the full new C++ spec in the permission prompt before tests/parser_test.cpp exists on disk.
- Atlas actually runs GoogleTest via ctest through bash, because a test that was never executed is not a test.
- C++ template errors can run to hundreds of lines; bash truncates at 2000 lines or 50 KB and saves the full log to a readable file.
- A todowrite list tracks still-untested symbols so a suite covering half a large C++ module is not mistaken for a finished one.

## How do you make sure no public C++ function is left untested?

Atlas enumerates the module's exported symbols with the lsp tool's documentSymbol operation before writing a single TEST case, which is step 1 of the documented workflow. In a C++ codebase that means reading include/parser.hpp and src/parser.cpp and getting back the real declared functions and class methods, not a guess at the public surface.

A C++ header is not a reliable list of what needs testing, because a class can declare methods in the header, define them in the .cpp, inherit others from a base class, and expose free functions in the same namespace. documentSymbol goes through the language server and returns the declared symbols as the compiler understands them. Atlas also indexes code by AST declarations using tree-sitter, not blind line windows, so when it reads a symbol it gets the whole declaration, template parameters and all, rather than a truncated window. The output is a checklist: one public function, one GoogleTest case at minimum.

## How does Atlas match the GoogleTest conventions a C++ repo already uses?

Atlas greps for an existing test file before writing a new one, step 2 of the documented workflow. In a C++ project that surfaces the repo's real conventions: whether tests use TEST or TEST_F, whether they include gtest/gtest.h directly, how tests/CMakeLists.txt registers targets, and the file naming pattern under tests/.

An AI-written C++ test that ignores the repo's conventions creates a second dialect in the same tree, and reviewers notice immediately. Atlas copies rather than invents: it greps tests/ for an existing spec, reads how that file sets up fixtures, includes headers, and links against the module under test, and mirrors that structure in the new file. The CMake registration matters as much as the test body, since a GoogleTest binary that is never added as a ctest target will never run. Atlas searches code with hybrid semantic and keyword retrieval fused by reciprocal rank fusion, so a query about how fixtures are constructed finds the pattern even when the word fixture is not in the source.

## Why does Atlas run GoogleTest via ctest instead of just writing the test file?

Atlas executes GoogleTest via ctest through the bash tool immediately after writing the spec, because a test that was never executed is not a test. Output over 2000 lines or 50 KB is truncated and the full log saved to a file, so even a noisy C++ compile error stays fully readable.

C++ punishes untested test code harder than most languages. A missing include, a linker error because the new test target was not wired into tests/CMakeLists.txt, an ambiguous overload in an EXPECT_EQ comparison: none of these show up until you build. Atlas runs GoogleTest via ctest with the bash tool and reads what comes back. Output over 2000 lines or 50 KB is truncated and the full log is saved to a file you can read, which matters because a single template error in C++ can generate hundreds of lines of instantiation trace. Every bash call is permission-gated against allow, ask, and deny rules before it runs.

## How does Atlas review a new C++ test file before it lands on disk?

Atlas's write tool shows the diff in the permission prompt before anything lands in tests/, which is step 3 of the documented workflow. For a new C++ spec you see the full contents of tests/parser_test.cpp, its includes, its TEST_F cases, and its fixture, and you approve or reject before the file exists.

Atlas computes a unified diff for every file edit and surfaces it for approval before writing, and the write tool is no exception: a brand new C++ test file is presented in full in the permission prompt. Every Atlas tool call is permission-gated against allow, ask, and deny rules before it runs, so the write to tests/ and the subsequent ctest invocation are separate, individually approved actions. Atlas also snapshots file changes as git patches, so even an approved test file that turns out to be wrong can be diffed and rolled back rather than manually deleted and reconstructed.

## How do you iterate to a green ctest run on a large untested C++ module?

Atlas iterates with the edit tool until the ctest suite is green, keeping progress in a todowrite list when the module is large. A C++ module with 30 public methods across include/ and src/ produces far more work than one turn holds, and the todowrite list is what keeps the untested half from being forgotten.

Iteration on a fresh C++ test suite is mostly compile errors, then assertion failures, then edge cases. Atlas fixes each with the edit tool, re-runs GoogleTest via ctest through bash, and reads the result. When the module is big enough that the work spans turns, the todowrite list carries the list of still-untested symbols forward, so a suite that covers 12 of 30 methods is never mistaken for a finished one. clang-format runs over the new spec so the diff is readable, and vcpkg is where any test-only dependency the suite needs is declared.

## Steps

1. Run atlas in a C++ project that has a CMakeLists.txt, so Atlas can read your headers, translation units, and build targets.
2. Read the module under test, then run the lsp tool's documentSymbol operation on it to enumerate every exported symbol so no public C++ function is missed.
3. Grep tests/ for an existing spec to copy the repo's real conventions: TEST versus TEST_F, the gtest/gtest.h include style, and the file naming pattern.
4. Check how tests/CMakeLists.txt registers existing GoogleTest targets, because a test binary that is never added as a ctest target will never run.
5. Write the new spec file with the write tool, which shows the diff in the permission prompt before anything lands on disk.
6. Run the suite with the bash tool, invoking GoogleTest via ctest, and read the failures; output over 2000 lines or 50 KB is truncated and the full log is saved to a file you can read.
7. Iterate with the edit tool through the compile errors and assertion failures until ctest is green, keeping progress in a todowrite list when the module is large.
8. Declare any test-only dependency through vcpkg and run clang-format over the new spec so the diff you review is substance rather than formatting.

## FAQ

### how to add googletest coverage to an untested c++ module with an AI agent

Atlas reads the module, runs the lsp tool's documentSymbol operation to enumerate its exported symbols, greps an existing test for the repo's conventions, writes the new spec with the write tool, and then runs GoogleTest via ctest with the bash tool. The run is the point: an unexecuted test is not a test.

### will atlas invent its own c++ test style or follow my repo's

Atlas copies the repo's existing test conventions rather than inventing its own. It greps tests/ for an existing spec to learn the framework, the include style, the TEST versus TEST_F choice, and the naming convention, then mirrors that in the new C++ file.

### does atlas actually compile and run c++ tests or just write them

Atlas runs them. After the write tool lands the spec, Atlas invokes GoogleTest via ctest through the bash tool and reads the failures. That catches the most common fresh-test failures in C++: a missing include, a linker error, or a test target never registered in tests/CMakeLists.txt.

### how does atlas handle huge c++ template compile errors in test output

Atlas's bash tool truncates output over 2000 lines or 50 KB and saves the complete log to a file you can read. A single template instantiation error in C++ can produce hundreds of lines, so the full log stays on disk while the model works from a bounded excerpt.

### can i review a c++ test file before atlas writes it to disk

Yes. The write tool shows the diff in the permission prompt before anything lands in tests/, so you see the full contents of the new spec, its includes, and its cases first. Every Atlas tool call is permission-gated against allow, ask, and deny rules before it runs.

### how do i make sure every public method in my c++ class gets a test

Run the lsp tool's documentSymbol operation on the module. It returns the declared symbols as the language server understands them, including methods defined in the .cpp rather than the header, which gives you an explicit checklist to cover with GoogleTest cases.

### does atlas work with cmake and vcpkg projects

Atlas is documented for C++ projects with CMake, headers, and modern standards. Run atlas in a project with a CMakeLists.txt, and it reads your headers, translation units, and build targets. vcpkg is the package manager and clang-format is the formatter in that toolchain.

### how does atlas track progress when adding tests to a large c++ module

Atlas keeps progress in a todowrite list. For a module with 30 public methods spread across include/ and src/, the todowrite list carries the still-untested symbols across turns so a suite that covers 12 of them is not mistaken for a finished one.

---

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