Diff-driven Android ViewModel test generation CLI
Detect changed ViewModels, plan tests, generate candidate local unit tests, and verify them with Gradle.
d2t1.0 focuses on one thing: turning changed Android ViewModels into verifiable local unit tests. The CLI is the primary product. The MCP app remains experimental.
Most Android test generation tools fail in one of two ways:
- they ignore the actual code diff and generate too much
- they generate code, but stop before verification
d2t is built around a narrower loop:
- detect changed
*ViewModel.ktfiles fromgit diff - analyze the changed ViewModel surface and collaborators
- build a scenario-first
TestPlan - generate candidate local unit tests
- verify those generated tests with Gradle
That makes it useful as a developer workflow tool, not just a code dump generator.
d2t 1.0 is intentionally narrow.
- Diff-driven Android ViewModel local unit test generation
- Gradle-backed verification of generated tests
- Bring-your-own API key support
- OpenAI Responses API support
- Anthropic Messages API support
- Gemini GenerateContent API support
- Custom
responses-compatibleendpoints - Custom
chat-completionsendpoints - Release ZIP and Homebrew distribution
- A transport-bound MCP server
- Instrumented
androidTestgeneration - Compose UI test generation
- Full end-to-end autonomous repair loops
- Perfect external classpath symbol resolution in every Android build graph
brew install gay00ung/diff2test-android/d2tOptional tap flow:
brew tap gay00ung/diff2test-android
brew install d2tDownload d2t.zip from the latest release:
unzip d2t.zip
cd d2t
./bin/d2t helpgit clone https://github.com/gay00ung/diff2test-android.git
cd diff2test-android
./gradlew test
./d2t helpd2t init[ai]
enabled = true
provider = "custom"
protocol = "chat-completions"
api_key_env = "LLM_API_KEY"
model = "qwen3-coder-next-mlx"
base_url = "http://127.0.0.1:12345/v1"
connect_timeout_seconds = 30
request_timeout_seconds = 300d2t doctord2t auto --aiIf you are running from source, use ./d2t instead of d2t.
d2t stores only the environment variable name for the API key in ~/.config/d2t/config.toml. Keep the secret itself in your shell environment.
Supported provider/protocol combinations:
provider = "openai"withprotocol = "responses-compatible"provider = "anthropic"withprotocol = "anthropic-messages"provider = "gemini"withprotocol = "gemini-generate-content"provider = "custom"withprotocol = "responses-compatible"provider = "custom"withprotocol = "chat-completions"
Example:
source ~/.zshrc
d2t doctor
d2t auto --aiAt a high level:
git diff
-> changed ViewModel detection
-> ViewModel analysis
-> TestPlan generation
-> AI or deterministic code generation
-> quality gate
-> Gradle verification
Important implementation details:
d2tdoes not ask the model to guess from the entire repo blindly- the diff and the analyzed ViewModel surface narrow the generation scope first
- generated tests must pass a built-in quality gate before verification
autogenerates and verifies in one command--repairenables one bounded repair pass for common import and coroutine-test utility issues
d2t init [--force]
d2t doctor
d2t scan
d2t plan path/to/SomeViewModel.kt
d2t generate path/to/SomeViewModel.kt --write [--ai|--no-ai] [--strict-ai]
d2t auto [--ai|--no-ai] [--strict-ai] [--model model-name] [--no-verify] [--repair]
d2t verify :module:testTask- make sure your current working tree actually contains a modified
*ViewModel.kt - or pass an explicit file path to
planorgenerate
- increase
request_timeout_seconds - try a smaller or faster model
- prefer
protocol = "chat-completions"when your gateway handles that path more reliably
- the generator produced code that
d2tconsiders too fragile or incomplete - this is usually a generation-quality problem, not a Gradle problem
- retry with a stronger model or add
--repairwhen verification is enabled
- inspect the generated test under
src/test/kotlin/...GeneratedTest.kt - run the printed Gradle verification command directly
- if the failure is import or coroutine utility related, retry with
d2t auto --ai --repair
apps/cli: main CLI applicationapps/mcp-server: experimental MCP-facing catalog scaffoldmodules/*: engine modulesprompts/*: prompt templates and policiesfixtures/*: sample app and verification fixturesdocs/*: architecture and release docs
This repository includes:
- Homebrew packaging via
packaging/homebrew/d2t.rb - release automation via
.github/workflows/release.yml - tag automation via
.github/workflows/tag-release.yml - distribution ZIP output via
./gradlew :apps:cli:distZip
The generated archive is written to:
apps/cli/build/distributions/d2t.zipThe CLI is the stable surface.
The MCP app is still experimental:
- it is useful as a catalog scaffold
- it is not yet positioned as a production transport-bound MCP server
For the current release gate and roadmap:
