TestGenAI
✨ A CLI gem that adds tests for untested methods in your code ✨
TestGenAI is a Ruby CLI gem for development environments that finds untested methods in your codebase and generates tests for them using an AI service. Point it at your project and it scans your code, finds methods with no test coverage, and asks an LLM to write tests for them, matching your existing style along the way.
Caution
TestGenAI is a work in progress and should not be used in production environments. While it works locally for me, it hasn't been tested in a wide variety of projects yet and may have many edge cases or bugs. Use with caution and please report any issues you encounter.
See this article for the motivation and design behind TestGenAI.
TestGenAI can scan your code two ways. If SimpleCov is available in your project, it runs your test suite with coverage tracking and finds methods where every line has zero hits, which correctly handles files that are only partially tested. Without SimpleCov, it falls back to checking whether a matching spec or test file exists for each source file. That's simpler, but it can't tell a partially tested file from a fully tested one, so a base class that's only exercised through subclass specs will show up as fully untested.
Stack
- Ruby 3.4.5
- Thor for the CLI
- ruby_llm to talk to LLM providers like Anthropic and OpenAI
- parser and prism for parsing and scanning Ruby source
- RSpec, StandardRB, Minitest, and SimpleCov for testing and linting the gem itself
Setup
Install
Add TestGenAI to your project's Gemfile in the development group, or
install the gem directly:
gem install testgenaiConfigure an LLM provider
TestGenAI needs an LLM provider to generate tests. Configure it via environment variables or CLI flags:
| Env var | Flag | Description |
|---|---|---|
TESTGENAI_PROVIDER |
--provider |
LLM provider (e.g. anthropic, openai) |
TESTGENAI_MODEL |
--model |
Model name (e.g. claude-opus-4-7) |
| — | --api-key |
API key (overrides env var set by the provider SDK) |
TESTGENAI_FRAMEWORK |
--test-framework, -t
|
Test framework: rspec (default) or minitest
|
TESTGENAI_OUTPUT_DIR |
--output-dir, -o
|
Output directory for generated tests |
TESTGENAI_PAUSE |
--pause, -p
|
Seconds to pause between API calls (default: 1) |
| — | --conventions |
Analyze project test patterns and include them in prompts |
Enable accurate scanning with SimpleCov
By default TestGenAI uses the file-existence scanner described above. If you
want the more accurate SimpleCov-based scanner, add SimpleCov to your project
and configure it to start when COVERAGE=true is set:
# Gemfile
gem "simplecov", require: false, group: [:development, :test]# spec/spec_helper.rb or test/test_helper.rb
if ENV["COVERAGE"]
require "simplecov"
SimpleCov.start
endWith this in place, TestGenAI runs your test suite with COVERAGE=true to
generate coverage/.resultset.json, then uses that data to find methods
where every executable line has zero hits, including methods in files that
are only partially tested. If coverage/.resultset.json already exists from
a previous run, TestGenAI uses it directly without re-running the test suite.
If SimpleCov isn't set up correctly, TestGenAI falls back to the file-existence scanner and prints one of these messages:
-
SimpleCov not found in Gemfile or gemspec. Using file-existence scanner.means SimpleCov isn't declared in yourGemfileor gemspec. -
Coverage generation failed. Using file-existence scanner.means SimpleCov was found, but running the suite withCOVERAGE=truedidn't producecoverage/.resultset.json. Check that SimpleCov is configured to start whenCOVERAGE=trueis set, and that your suite runs cleanly withCOVERAGE=true bundle exec rspec(or the minitest equivalent).
Tasks
Run everything through the bin/testgenai executable once it's installed:
testgenai scan Scan for untested methods and report them
testgenai context Scan and show the LLM context that would be sent (diagnostic)
testgenai generate Full pipeline: scan → context → generate → validate
testgenai version Show version
testgenai help Show help
scan
Finds untested methods and prints them. No API calls are made.
bin/testgenai scan
bin/testgenai scan --test-framework minitestcontext
Like scan, but also prints the context snippet that would be sent to the
LLM for each method. Useful for inspecting what the generator will see
before running a full generate.
generate
Runs the full pipeline: scan, build context, call the LLM, validate the generated tests, and report results.
bin/testgenai generate --provider anthropic --model claude-opus-4-7
bin/testgenai generate --provider anthropic --model claude-opus-4-7 --conventionsGenerated tests are injected into existing spec/test files when they exist,
or written to new files mirroring the source path under spec/ (rspec) or
test/ (minitest). If validation fails after injection, the original file is
restored and the generated tests are saved to a per-method fallback file
(e.g. widget_render_spec.rb) for manual review.
The --conventions flag analyzes your existing test suite to detect patterns
(naming conventions, shared contexts, matchers, etc.) and includes them in
the LLM prompt so generated tests match your project's style. The analysis
result is cached in spec/conventions.md (or test/conventions.md) and
refreshed automatically when your test files change.
mise tasks
This repo also uses mise to run the gem's own test suite and linter:
-
mise run testruns the RSpec suite (bundle exec rspec) -
mise run lintruns the StandardRB style check (bundle exec standardrb)
Documentation
Design docs and implementation plans for each major feature live under docs/:
-
docs/specs/has the design docs for the initial build, the SimpleCov integration, and the conventions extractor -
docs/plans/has the implementation plan that goes with each spec
License
TestGenAI is released under the MIT License. See LICENSE for the full text.