Test Generator — Framework-Aware Test Scaffolding
You are generating and optionally running tests for source files in the current project, matching the project's existing test framework and conventions.
Arguments
$ARGUMENTS may contain any combination of:
| Flag |
Effect |
path/to/file.ext |
Target a specific file for test generation |
--framework <name> |
Override detected framework (pytest, jest, vitest, go, cargo, mocha, rspec, phpunit) |
--update |
Add tests to an existing test file instead of creating a new one |
--run |
Run tests after writing to verify they pass |
--coverage |
Focus on untested public functions, skip already-tested code |
| (plain text) |
Specific behavior or scenarios to test |
Step 1: Identify Target Files
Determine which files to generate tests for:
- Explicit path in
$ARGUMENTS — use the specified file(s).
- No path specified — auto-detect from recent changes:
- Run
git diff --name-only HEAD for unstaged changes
- Run
git diff --name-only --cached for staged changes
- Filter to source files only (exclude tests, configs, lockfiles, docs)
- If no changes are found and no path was given, tell the user to specify a file and stop.
Read each target file in full using the Read tool.
Step 2: Detect Test Framework
Check project configuration files to determine the test framework:
| Config File |
Framework |
pyproject.toml with [tool.pytest] or pytest.ini or conftest.py |
pytest |
package.json with jest in devDependencies or jest.config.* |
Jest |
package.json with vitest in devDependencies or vitest.config.* |
Vitest |
go.mod |
Go testing |
Cargo.toml |
Rust #[cfg(test)] |
package.json with mocha in devDependencies or .mocharc.* |
Mocha |
Gemfile with rspec or .rspec |
RSpec |
composer.json with phpunit or phpunit.xml |
PHPUnit |
If --framework was specified, use that instead of auto-detection.
If no framework is detected, infer from the target file's language:
- Python -> pytest
- JavaScript/TypeScript -> Jest
- Go -> Go testing
- Rust -> Rust built-in tests
Step 3: Learn Project Test Conventions
Read 2-3 existing test files to extract patterns:
- Find existing tests — search for files matching common test patterns:
test_*.py, *_test.py, tests/, __tests__/
*.test.ts, *.spec.ts, *.test.js, *.spec.js
*_test.go
tests/ directory in Rust crates
- Extract patterns from existing tests:
- Naming:
test_<function>, describe/it blocks, Test<Struct> functions
- File location: colocated (
src/foo.test.ts) vs separate directory (tests/test_foo.py)
- Imports: how the project imports test utilities, fixtures, mocks
- Assertion style:
assert, expect(), assertEqual, custom matchers
- Setup/teardown: fixtures,
beforeEach, setUp, test helpers
- Mocking: how external dependencies are mocked (mock libraries, dependency injection, test doubles)
- If no existing tests are found, use the framework's standard conventions.
Step 4: Determine Test File Path
Follow the project's existing convention for test file placement:
| Convention |
Example |
| Colocated |
src/utils.ts -> src/utils.test.ts |
| Mirror directory |
src/utils.py -> tests/test_utils.py |
| Same package (Go) |
pkg/handler.go -> pkg/handler_test.go |
| Inline (Rust) |
Tests go in #[cfg(test)] mod tests at bottom of source file |
If --update was specified, find and use the existing test file for this source file.
Step 5: Analyze Target Code
For each target file, identify what to test:
- Public API — exported functions, classes, methods, types
- Branching logic — if/else, match/switch, early returns, guard clauses
- Error paths — try/catch, Result/Option handling, error returns, validation failures
- Edge cases — empty inputs, boundary values, nil/null/undefined, zero, negative numbers, empty collections
- Side effects — database calls, network requests, file I/O, environment variable reads (these need mocking)
If --coverage was specified:
- Read the existing test file for this source
- Identify which public functions already have tests
- Only generate tests for untested functions
Step 6: Generate Tests
Write tests following these principles:
Structure
- One test per behavior — each test verifies a single logical behavior, not a single function
- Arrange-Act-Assert — clear separation of setup, execution, and verification
- Descriptive names — test names describe the scenario and expected outcome, e.g.,
test_parse_returns_none_for_empty_input
What to Test
- Happy path with typical inputs
- Edge cases identified in Step 5
- Error paths and validation failures
- Boundary conditions (empty, single element, max values)
- Return values AND side effects where relevant
What NOT to Test
- Private/internal functions directly (test through public API)
- Third-party library behavior
- Trivial getters/setters with no logic
- Implementation details that could change without affecting behavior
Mocking
- Mock external dependencies only (network, database, filesystem, time)
- Do NOT mock the code under test
- Use the project's existing mock patterns (from Step 3)
- Prefer dependency injection over monkey-patching when possible
Test Quality
- Tests should fail for the right reasons — a test that never fails is useless
- Avoid brittle assertions on exact strings, timestamps, or ordering unless order is part of the contract
- Use factory functions or fixtures for complex test data instead of inline object literals
Step 7: Write Test File
Creating a new test file:
Use the Write tool. Include all necessary imports, fixtures, and the generated tests.
Updating an existing test file (--update):
Use the Edit tool. Add new test functions after the existing ones, maintaining the file's import style and organization.
After writing, show a summary:
## Tests Generated
| Source File | Test File | Tests Added |
|-------------|-----------|-------------|
| `path/to/source.py` | `tests/test_source.py` | 8 |
### Test Inventory
- `test_function_a_returns_expected_output` — happy path
- `test_function_a_raises_on_empty_input` — edge case
- `test_function_b_handles_network_error` — error path
...
Step 8: Run Tests (if --run)
If --run was specified in $ARGUMENTS:
Execute tests using the detected framework:
- pytest:
pytest path/to/test_file.py -v
- Jest:
npx jest path/to/test_file --verbose
- Vitest:
npx vitest run path/to/test_file --reporter=verbose
- Go:
go test ./path/to/package/ -v -run TestName
- Cargo:
cargo test test_module_name -- --nocapture
- Mocha:
npx mocha path/to/test_file
- RSpec:
bundle exec rspec path/to/spec_file
If tests fail, analyze the failure:
After tests pass (or after 3 failed retries), show results:
## Test Results
Passed: N
Failed: N
Skipped: N
Total: N
Composability
After generating tests, suggest next steps:
- "Run
/commit to commit the new tests."
- If source bugs were found: "Consider running
/review on the source file to investigate further."
- If
--run wasn't used: "Add --run to execute the tests and verify they pass."
Edge Cases
- No test framework detected and no
--framework: Default based on language. If the language is ambiguous, ask the user which framework to use.
- Target file is already a test file: Tell the user and stop. Don't generate tests for tests.
- Target file doesn't exist: Tell the user the file wasn't found and stop.
- Generated file has no public API: Warn the user there's nothing to test publicly. Offer to test internal functions if the user confirms.
- Rust inline tests: When the convention is inline
#[cfg(test)] modules, use Edit to append the test module to the source file instead of creating a separate file.
- Monorepo: If the project has multiple packages (workspace), detect and use the correct package's test config.
1---2name: test3description: Generate and run tests for specified files, auto-detecting the project's test framework and conventions4---56# Test Generator — Framework-Aware Test Scaffolding78You are generating and optionally running tests for source files in the current project, matching the project's existing test framework and conventions.910## Arguments1112`$ARGUMENTS` may contain any combination of:1314| Flag | Effect |15|------|--------|16| `path/to/file.ext` | Target a specific file for test generation |17| `--framework <name>` | Override detected framework (pytest, jest, vitest, go, cargo, mocha, rspec, phpunit) |18| `--update` | Add tests to an existing test file instead of creating a new one |19| `--run` | Run tests after writing to verify they pass |20| `--coverage` | Focus on untested public functions, skip already-tested code |21| *(plain text)* | Specific behavior or scenarios to test |2223## Step 1: Identify Target Files2425Determine which files to generate tests for:26271. **Explicit path in `$ARGUMENTS`** — use the specified file(s).282. **No path specified** — auto-detect from recent changes:29 - Run `git diff --name-only HEAD` for unstaged changes30 - Run `git diff --name-only --cached` for staged changes31 - Filter to source files only (exclude tests, configs, lockfiles, docs)323. If no changes are found and no path was given, tell the user to specify a file and stop.3334Read each target file in full using the Read tool.3536## Step 2: Detect Test Framework3738Check project configuration files to determine the test framework:3940| Config File | Framework |41|-------------|-----------|42| `pyproject.toml` with `[tool.pytest]` or `pytest.ini` or `conftest.py` | pytest |43| `package.json` with `jest` in devDependencies or `jest.config.*` | Jest |44| `package.json` with `vitest` in devDependencies or `vitest.config.*` | Vitest |45| `go.mod` | Go testing |46| `Cargo.toml` | Rust `#[cfg(test)]` |47| `package.json` with `mocha` in devDependencies or `.mocharc.*` | Mocha |48| `Gemfile` with `rspec` or `.rspec` | RSpec |49| `composer.json` with `phpunit` or `phpunit.xml` | PHPUnit |5051If `--framework` was specified, use that instead of auto-detection.5253If no framework is detected, infer from the target file's language:54- Python -> pytest55- JavaScript/TypeScript -> Jest56- Go -> Go testing57- Rust -> Rust built-in tests5859## Step 3: Learn Project Test Conventions6061Read 2-3 existing test files to extract patterns:62631. **Find existing tests** — search for files matching common test patterns:64 - `test_*.py`, `*_test.py`, `tests/`, `__tests__/`65 - `*.test.ts`, `*.spec.ts`, `*.test.js`, `*.spec.js`66 - `*_test.go`67 - `tests/` directory in Rust crates682. **Extract patterns** from existing tests:69 - **Naming**: `test_<function>`, `describe/it` blocks, `Test<Struct>` functions70 - **File location**: colocated (`src/foo.test.ts`) vs separate directory (`tests/test_foo.py`)71 - **Imports**: how the project imports test utilities, fixtures, mocks72 - **Assertion style**: `assert`, `expect()`, `assertEqual`, custom matchers73 - **Setup/teardown**: fixtures, `beforeEach`, `setUp`, test helpers74 - **Mocking**: how external dependencies are mocked (mock libraries, dependency injection, test doubles)753. If no existing tests are found, use the framework's standard conventions.7677## Step 4: Determine Test File Path7879Follow the project's existing convention for test file placement:8081| Convention | Example |82|------------|---------|83| Colocated | `src/utils.ts` -> `src/utils.test.ts` |84| Mirror directory | `src/utils.py` -> `tests/test_utils.py` |85| Same package (Go) | `pkg/handler.go` -> `pkg/handler_test.go` |86| Inline (Rust) | Tests go in `#[cfg(test)] mod tests` at bottom of source file |8788If `--update` was specified, find and use the existing test file for this source file.8990## Step 5: Analyze Target Code9192For each target file, identify what to test:93941. **Public API** — exported functions, classes, methods, types952. **Branching logic** — if/else, match/switch, early returns, guard clauses963. **Error paths** — try/catch, Result/Option handling, error returns, validation failures974. **Edge cases** — empty inputs, boundary values, nil/null/undefined, zero, negative numbers, empty collections985. **Side effects** — database calls, network requests, file I/O, environment variable reads (these need mocking)99100If `--coverage` was specified:1011. Read the existing test file for this source1022. Identify which public functions already have tests1033. Only generate tests for untested functions104105## Step 6: Generate Tests106107Write tests following these principles:108109### Structure110- **One test per behavior** — each test verifies a single logical behavior, not a single function111- **Arrange-Act-Assert** — clear separation of setup, execution, and verification112- **Descriptive names** — test names describe the scenario and expected outcome, e.g., `test_parse_returns_none_for_empty_input`113114### What to Test115- Happy path with typical inputs116- Edge cases identified in Step 5117- Error paths and validation failures118- Boundary conditions (empty, single element, max values)119- Return values AND side effects where relevant120121### What NOT to Test122- Private/internal functions directly (test through public API)123- Third-party library behavior124- Trivial getters/setters with no logic125- Implementation details that could change without affecting behavior126127### Mocking128- Mock external dependencies only (network, database, filesystem, time)129- Do NOT mock the code under test130- Use the project's existing mock patterns (from Step 3)131- Prefer dependency injection over monkey-patching when possible132133### Test Quality134- Tests should fail for the right reasons — a test that never fails is useless135- Avoid brittle assertions on exact strings, timestamps, or ordering unless order is part of the contract136- Use factory functions or fixtures for complex test data instead of inline object literals137138## Step 7: Write Test File139140### Creating a new test file:141Use the Write tool. Include all necessary imports, fixtures, and the generated tests.142143### Updating an existing test file (`--update`):144Use the Edit tool. Add new test functions after the existing ones, maintaining the file's import style and organization.145146### After writing, show a summary:147148```149## Tests Generated150151| Source File | Test File | Tests Added |152|-------------|-----------|-------------|153| `path/to/source.py` | `tests/test_source.py` | 8 |154155### Test Inventory156- `test_function_a_returns_expected_output` — happy path157- `test_function_a_raises_on_empty_input` — edge case158- `test_function_b_handles_network_error` — error path159...160```161162## Step 8: Run Tests (if `--run`)163164If `--run` was specified in `$ARGUMENTS`:1651661. **Execute tests** using the detected framework:167 - pytest: `pytest path/to/test_file.py -v`168 - Jest: `npx jest path/to/test_file --verbose`169 - Vitest: `npx vitest run path/to/test_file --reporter=verbose`170 - Go: `go test ./path/to/package/ -v -run TestName`171 - Cargo: `cargo test test_module_name -- --nocapture`172 - Mocha: `npx mocha path/to/test_file`173 - RSpec: `bundle exec rspec path/to/spec_file`1741752. **If tests fail**, analyze the failure:176 - **Test-side bug** (wrong assertion, missing mock, import error) — fix the test and retry. Up to 3 retries.177 - **Source-side bug** (the test correctly caught a real bug) — report it to the user, do NOT modify the source code. Format as:178 ```179 ## Source Bug Detected180181 **File:** `path/to/source.py:42`182 **Test:** `test_function_a_raises_on_empty_input`183 **Issue:** [Description of the bug the test revealed]184 ```1851863. **After tests pass** (or after 3 failed retries), show results:187 ```188 ## Test Results189190 Passed: N191 Failed: N192 Skipped: N193 Total: N194 ```195196## Composability197198After generating tests, suggest next steps:199200- "Run `/commit` to commit the new tests."201- If source bugs were found: "Consider running `/review` on the source file to investigate further."202- If `--run` wasn't used: "Add `--run` to execute the tests and verify they pass."203204## Edge Cases205206- **No test framework detected and no `--framework`**: Default based on language. If the language is ambiguous, ask the user which framework to use.207- **Target file is already a test file**: Tell the user and stop. Don't generate tests for tests.208- **Target file doesn't exist**: Tell the user the file wasn't found and stop.209- **Generated file has no public API**: Warn the user there's nothing to test publicly. Offer to test internal functions if the user confirms.210- **Rust inline tests**: When the convention is inline `#[cfg(test)]` modules, use Edit to append the test module to the source file instead of creating a separate file.211- **Monorepo**: If the project has multiple packages (workspace), detect and use the correct package's test config.