{
  "markdown": "# test-generator\n\nA 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.\n\n## What It Does\n\n- Detects your test framework (RSpec, pytest, Jest, Vitest, PHPUnit, Go testing, ExUnit, Rust)\n- Maps source files to the correct test file paths\n- Generates tests covering happy path, edge cases, and error cases\n- PostToolUse hook reminds you when edited files don't have tests\n- Matches your project's existing test style and conventions\n\n## Installation\n\n```\nclaude plugin install test-generator\n```\n\n## Usage\n\n### Slash Command\n\n```\n/generate-tests                          # Scan entire project\n/generate-tests app/models/user.rb       # Generate tests for one file\n/generate-tests src/utils/               # Generate tests for a directory\n```\n\n### Automatic Reminders (Hook)\n\nAfter you edit a source file without a corresponding test file, the plugin prints:\n\n```\nNo test file found for user.rb.\nExpected test at: spec/models/user_spec.rb\nRun /generate-tests app/models/user.rb to create one.\n```\n\nDisable with:\n```\nDISABLE_TEST_REMINDER=1\n```\n\n### Skill (Auto-Activated)\n\nThe `auto-test` skill activates when you:\n- Create a new source file\n- Add new public methods\n- Ask about testing or mention TDD/coverage\n\n### Agent\n\nThe `test-writer` agent does deep analysis - reads existing tests for style, understands dependencies, mocks external services, and generates comprehensive test suites.\n\n## Supported Frameworks\n\n| Language | Frameworks | Test Path Convention |\n|---|---|---|\n| Ruby | RSpec, Minitest | `spec/**/*_spec.rb`, `test/**/*_test.rb` |\n| Python | pytest, unittest | `tests/test_*.py` |\n| JS/TS | Jest, Vitest, Mocha | `__tests__/*.test.ts`, `*.spec.ts` |\n| PHP | PHPUnit | `tests/Unit/*Test.php`, `tests/Feature/*Test.php` |\n| Go | testing, testify | `*_test.go` (same directory) |\n| Elixir | ExUnit | `test/*_test.exs` |\n| Rust | cargo test | `#[cfg(test)]` inline or `tests/*.rs` |\n\n## Test Quality\n\nGenerated tests follow these principles:\n- One behavior per test\n- Descriptive names: `it \"returns nil when user not found\"`\n- Arrange-Act-Assert pattern\n- Minimal setup, no shared mutable state\n- Real objects over mocks when possible\n- Mocks for external services (APIs, email, file system)\n- Uses factories/fixtures matching your project conventions\n\n## Examples\n\n### Ruby/RSpec - Model test\n\nSource: `app/models/user.rb`\n```ruby\nclass User < ApplicationRecord\n  def full_name\n    \"#{first_name} #{last_name}\"\n  end\n\n  def active?\n    !deactivated_at\n  end\nend\n```\n\nGenerated: `spec/models/user_spec.rb`\n```ruby\nrequire \"rails_helper\"\n\nRSpec.describe User do\n  describe \"#full_name\" do\n    it \"combines first and last name\" do\n      user = build(:user, first_name: \"Jane\", last_name: \"Doe\")\n      expect(user.full_name).to eq(\"Jane Doe\")\n    end\n\n    it \"handles nil first name\" do\n      user = build(:user, first_name: nil, last_name: \"Doe\")\n      expect(user.full_name).to eq(\" Doe\")\n    end\n  end\n\n  describe \"#active?\" do\n    it \"returns true when not deactivated\" do\n      user = build(:user, deactivated_at: nil)\n      expect(user).to be_active\n    end\n\n    it \"returns false when deactivated\" do\n      user = build(:user, deactivated_at: Time.current)\n      expect(user).not_to be_active\n    end\n  end\nend\n```\n\n### Python/pytest - Service test\n\nSource: `src/services/auth.py`\n```python\ndef authenticate(email, password):\n    user = User.find_by_email(email)\n    if not user:\n        raise UserNotFoundError(email)\n    if not user.verify_password(password):\n        raise InvalidPasswordError()\n    return create_token(user)\n```\n\nGenerated: `tests/test_auth.py`\n```python\nimport pytest\nfrom unittest.mock import patch, MagicMock\nfrom src.services.auth import authenticate, UserNotFoundError, InvalidPasswordError\n\nclass TestAuthenticate:\n    def test_returns_token_for_valid_credentials(self):\n        user = MagicMock()\n        user.verify_password.return_value = True\n        with patch(\"src.services.auth.User\") as MockUser:\n            MockUser.find_by_email.return_value = user\n            token = authenticate(\"a@b.com\", \"pass123\")\n            assert token is not None\n\n    def test_raises_when_user_not_found(self):\n        with patch(\"src.services.auth.User\") as MockUser:\n            MockUser.find_by_email.return_value = None\n            with pytest.raises(UserNotFoundError):\n                authenticate(\"missing@b.com\", \"pass\")\n\n    def test_raises_when_password_invalid(self):\n        user = MagicMock()\n        user.verify_password.return_value = False\n        with patch(\"src.services.auth.User\") as MockUser:\n            MockUser.find_by_email.return_value = user\n            with pytest.raises(InvalidPasswordError):\n                authenticate(\"a@b.com\", \"wrong\")\n```\n\n## License\n\nMIT\n",
  "bytes": 4860,
  "sha": "32cfde64f84135c700fbc99beac42742c3acbc7878379f6252f77a3cd16c0ae7",
  "repo_slug": "a-abdellatif98/test-generator",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/plg_a_abdellatif98_test_generator_test_gener_971268a7/readme"
}