Back to the catalog

test-generator

Auto-generates test files when you write new code. Detects your test framework (RSpec, pytest, Jest, Vitest, PHPUnit, Go testing, ExUnit, Ru

Open source Open in the app JSON README (API)

About

Auto-generates test files when you write new code. Detects your test framework (RSpec, pytest, Jest, Vitest, PHPUnit, Go testing, ExUnit, Rust) and scaffolds comprehensive test suites covering happy path, edge cases, and error handling. A PostToolUse hook reminds you when edited source files lack a corresponding test file, and the /generate-tests command scans your project for untested code. Matches your project's existing test style, uses factories/fixtures, and mocks external dependencies automatically.

Details

Kind
Plugins
Topic
Developer tools
Publisher
a-abdellatif98
Origin
marketplace
Category
ferramentas
Last push
2026-03-10T11:34:13Z
Repository state
ativo
Language
Python
License
MIT
Added
2026-08-30 01:48:58
Updated
2026-08-30 01:48:58
Origin id
a-abdellatif98/test-generator/test-generator

README

# test-generator

A Claude Code plugin that auto-generates test files when you write new code. Detects your test framework, scaffolds tests with edge cases, and reminds you when source files lack coverage.

## What It Does

- Detects your test framework (RSpec, pytest, Jest, Vitest, PHPUnit, Go testing, ExUnit, Rust)
- Maps source files to the correct test file paths
- Generates tests covering happy path, edge cases, and error cases
- PostToolUse hook reminds you when edited files don't have tests
- Matches your project's existing test style and conventions

## Installation

```
claude plugin install test-generator
```

## Usage

### Slash Command

```
/generate-tests                          # Scan entire project
/generate-tests app/models/user.rb       # Generate tests for one file
/generate-tests src/utils/               # Generate tests for a directory
```

### Automatic Reminders (Hook)

After you edit a source file without a corresponding test file, the plugin prints:

```
No test file found for user.rb.
Expected test at: spec/models/user_spec.rb
Run /generate-tests app/models/user.rb to create one.
```

Disable with:
```
DISABLE_TEST_REMINDER=1
```

### Skill (Auto-Activated)

The `auto-test` skill activates when you:
- Create a new source file
- Add new public methods
- Ask about testing or mention TDD/coverage

### Agent

The `test-writer` agent does deep analysis - reads existing tests for style, understands dependencies, mocks external services, and generates comprehensive test suites.

## Supported Frameworks

| Language | Frameworks | Test Path Convention |
|---|---|---|
| Ruby | RSpec, Minitest | `spec/**/*_spec.rb`, `test/**/*_test.rb` |
| Python | pytest, unittest | `tests/test_*.py` |
| JS/TS | Jest, Vitest, Mocha | `__tests__/*.test.ts`, `*.spec.ts` |
| PHP | PHPUnit | `tests/Unit/*Test.php`, `tests/Feature/*Test.php` |
| Go | testing, testify | `*_test.go` (same directory) |
| Elixir | ExUnit | `test/*_test.exs` |
| Rust | cargo test | `#[cfg(test)]` inline or `tests/*.rs` |

## Test Quality

Generated tests follow these principles:
- One behavior per test
- Descriptive names: `it "returns nil when user not found"`
- Arrange-Act-Assert pattern
- Minimal setup, no shared mutable state
- Real objects over mocks when possible
- Mocks for external services (APIs, email, file system)
- Uses factories/fixtures matching your project conventions

## Examples

### Ruby/RSpec - Model test

Source: `app/models/user.rb`
```ruby
class User < ApplicationRecord
  def full_name
    "#{first_name} #{last_name}"
  end

  def active?
    !deactivated_at
  end
end
```

Generated: `spec/models/user_spec.rb`
```ruby
require "rails_helper"

RSpec.describe User do
  describe "#full_name" do
    it "combines first and last name" do
      user = build(:user, first_name: "Jane", last_name: "Doe")
      expect(user.full_name).to eq("Jane Doe")
    end

    it "handles nil first name" do
      user = build(:user, first_name: nil, last_name: "Doe")
      expect(user.full_name).to eq(" Doe")
    end
  end

  describe "#active?" do
    it "returns true when not deactivated" do
      user = build(:user, deactivated_at: nil)
      expect(user).to be_active
    end

    it "returns false when deactivated" do
      user = build(:user, deactivated_at: Time.current)
      expect(user).not_to be_active
    end
  end
end
```

### Python/pytest - Service test

Source: `src/services/auth.py`
```python
def authenticate(email, password):
    user = User.find_by_email(email)
    if not user:
        raise UserNotFoundError(email)
    if not user.verify_password(password):
        raise InvalidPasswordError()
    return create_token(user)
```

Generated: `tests/test_auth.py`
```python
import pytest
from unittest.mock import patch, MagicMock
from src.services.auth import authenticate, UserNotFoundError, InvalidPasswordError

class TestAuthenticate:
    def test_returns_token_for_valid_credentials(self):
        user = MagicMock()
        user.verify_password.return_value = True
        with patch("src.services.auth.User") as MockUser:
            MockUser.find_by_email.return_value = user
            token = authenticate("a@b.com", "pass123")
            assert token is not None

    def test_raises_when_user_not_found(self):
        with patch("src.services.auth.User") as MockUser:
            MockUser.find_by_email.return_value = None
            with pytest.raises(UserNotFoundError):
                authenticate("missing@b.com", "pass")

    def test_raises_when_password_invalid(self):
        user = MagicMock()
        user.verify_password.return_value = False
        with patch("src.services.auth.User") as MockUser:
            MockUser.find_by_email.return_value = user
            with pytest.raises(InvalidPasswordError):
                authenticate("a@b.com", "wrong")
```

## License

MIT

More