test-generator について
仕様やコードを基に、プロジェクトの既存ルールに沿ったテストを生成するプロンプト駆動型スキルです。ユニット、統合、API、エンドツーエンドテストを追加し、カバレッジや実行可能性を確認したい開発者向けです。
主な機能
- 01プロジェクトの規約に沿ったテスト生成
- 02ユニット・統合・API・E2Eテストに対応
- 03境界条件とエラーケースの分析
- 04構文・設定・カバレッジの確認
活用シーン
- 01新しいコンポーネントや関数のテスト追加
- 02APIエンドポイントのテスト作成
- 03ユーザーフローのE2Eテスト作成
- 04既存コードのテストカバレッジ確認
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ oimiragieo/ agent-studio --skill test-generatorインストール後、Claude Code で/test-generatorを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
commands/test-generator.mdhooks/post-execute.cjspre-execute.cjsreferences/research-requirements.mdrules/test-generator.mdschemas/input.schema.jsonoutput.schema.jsonscripts/main.cjstemplates/implementation-template.md詳細
モード:コグニティブ/プロンプト主導 — 単独で実行するユーティリティスクリプトはありません。エージェントのコンテキストを通じて使用します。
テスト生成スキル — プロジェクトのテストパターンと規約に従って、仕様、コンポーネント、API エンドポイントからテストコードを生成します。 - 新しいコンポーネントのテストを生成する - API エンドポイントのテストを作成する - ユーザーフローの E2E テストを生成する - 統合テストを作成する - 既存コードのテストカバレッジを追加するステップ 1:テストの種類を特定する
必要なテストの種類を判断します。
- ユニットテスト:コンポーネント/関数のテスト
- 統合テスト:サービス/API の統合テスト
- E2E テスト:ユーザーフロー全体のテスト
- API テスト:エンドポイントのテスト
ステップ 2:対象コードを分析する
テスト対象のコードを調べます(Parallel Read/Grep/Glob を使用)。
- コンポーネント/関数のコードを読む
- テストケースを特定する
- 依存関係を把握する
- エッジケースを確認する
ステップ 3:テストパターンを分析する
既存のテストを確認します。
- 類似するテストファイルを読む
- テストパターンを特定する
- テストフレームワークの使用方法を確認する
- モック戦略を把握する
ステップ 4:テストコードを生成する
パターンに従ってテストを作成します。
- 適切なテストフレームワークを使用する
- プロジェクトの規約に従う
- 網羅的なカバレッジを含める
- エッジケースとエラーシナリオを追加する
ステップ 5:カバレッジを分析する
テストを生成したら、カバレッジを分析します。
-
生成したテストがすべての要件を網羅していることを確認する:
- すべての関数/メソッドがテストされていることを確認する
- すべての分岐(if/else、switch など)が網羅されていることを確認する
- すべてのエッジケースがテストされていることを確認する
- エラーシナリオが網羅されていることを確認する
-
テストを実行できることを検証する:
- テストの構文が有効であることを確認する
- インポートが正しいことを確認する
- テストフレームワークが適切に設定されていることを確認する
- テストのセットアップ/ティアダウンが正しいことを検証する
-
カバレッジ率を報告する:
- 行カバレッジを算出する(可能な場合)
- 分岐カバレッジを算出する(可能な場合)
- 未カバーのコードパスを報告する
- 未カバーの箇所に対する追加テストを提案する
-
カバレッジ検証チェックリスト:
- すべての公開関数/メソッドにテストがある
- すべてのエラーパスがテストされている
- すべてのエッジケースが網羅されている
- テストの構文が有効である
- テストを正常に実行できる
- カバレッジがプロジェクトのしきい値を満たしている(定義されている場合) </execution_process>
import { render, screen, waitFor } from '@testing-library/react'
import { describe, it, expect, vi } from 'vitest'
import { UserProfile } from './user-profile'
describe('UserProfile', () => {
it('renders user information', async () => {
const mockUser = { id: '1', name: 'John', email: '[email protected]' }
render(<UserProfile user={mockUser} />)
await waitFor(() => {
expect(screen.getByText('John')).toBeInTheDocument()
expect(screen.getByText('[email protected]')).toBeInTheDocument()
})
})
it('handles loading state', () => {
render(<UserProfile user={null} loading />)
expect(screen.getByTestId('loading')).toBeInTheDocument()
})
it('handles error state', () => {
render(<UserProfile user={null} error="Failed to load" />)
expect(screen.getByText('Failed to load')).toBeInTheDocument()
})
})
</code_example>
<code_example> 統合テスト(API)
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { createTestClient } from './test-client';
describe('Users API', () => {
let client: TestClient;
beforeAll(() => {
client = createTestClient();
});
afterAll(async () => {
await client.cleanup();
});
it('creates a user', async () => {
const response = await client.post('/api/users', {
email: '[email protected]',
name: 'Test User',
});
expect(response.status).toBe(201);
expect(response.data).toHaveProperty('id');
expect(response.data.email).toBe('[email protected]');
});
it('validates required fields', async () => {
const response = await client.post('/api/users', {});
expect(response.status).toBe(400);
expect(response.data).toHaveProperty('errors');
});
});
</code_example>
<code_example> E2E テスト(Cypress)
describe('User Authentication Flow', () => {
beforeEach(() => {
cy.visit('/login');
});
it('allows user to login', () => {
cy.get('[data-testid="email-input"]').type('[email protected]');
cy.get('[data-testid="password-input"]').type('password123');
cy.get('[data-testid="login-button"]').click();
cy.url().should('include', '/dashboard');
cy.get('[data-testid="user-menu"]').should('be.visible');
});
it('shows error for invalid credentials', () => {
cy.get('[data-testid="email-input"]').type('[email protected]');
cy.get('[data-testid="password-input"]').type('wrong');
cy.get('[data-testid="login-button"]').click();
cy.get('[data-testid="error-message"]')
.should('be.visible')
.and('contain', 'Invalid credentials');
});
});
</code_example>
**Developer Agent との統合**: - 開発中にテストを生成する - テストカバレッジを確保する - 実装を検証するQA Agent との統合:
- 包括的なテストスイートを作成する
- テスト計画を生成する
- テストの品質を検証する
<best_practices>
- パターンに従う:既存のテスト構造に合わせる
- 包括的なカバレッジ:正常系とエッジケースをテストする
- 明確なテスト名:テスト内容を説明する名前を付ける
- テストを分離する:各テストを独立させる
- 依存関係をモックする:適切なモック戦略を使用する </best_practices>
# Generate tests for a file
node .claude/skills/test-generator/scripts/main.cjs src/components/UserProfile.tsx
# The tool will analyze the file and generate appropriate tests
</usage_example>
絶対遵守事項
- 必ずテストコードを生成する前に、既存のテストパターンとフレームワークの規約を分析する
- 実装の詳細を調べるテストを決して生成しない。公開された振る舞いと出力のみをテストする
- 必ずテスト対象の各単位について、null/undefined の入力、境界値、エラーシナリオなどのエッジケースを含める
- 変更可能な共有状態を持つテストを決して作成しない。beforeEach/afterEach を使って各テストを分離する
- テスト生成の完了とする前に、生成したテストの構文が有効で、実行可能であることを必ず確認する
アンチパターン
| アンチパターン | 失敗する理由 | 正しい方法 |
|---|---|---|
| 実装の詳細をテストする | 動作が変わっていなくても、リファクタリングでテストが失敗します | パブリック API の動作と観測可能な出力をテストします |
| テスト本体にアサーションがない | テストは常に成功し、何も検出しません | すべてのテストケースに明示的なアサーションを追加します |
| テスト間で変更可能な状態を共有する | 実行順序によってテストが失敗します | beforeEach/afterEach を使用して完全に分離します |
| アサーションにマジックナンバーを使う | 期待値が不明確になり、テストが壊れやすくなります | 名前付き定数または説明的なフィクスチャデータを使用します |
| エラーパスのテストがない | カバレッジが不十分になり、本番環境で障害が見過ごされます | 成功と失敗の両方のシナリオをテストします |
メモリープロトコル(必須)
開始前:
.claude/context/memory/learnings.md を読みます
完了後:
- 新しいパターン ->
.claude/context/memory/learnings.md - 見つかった問題 ->
.claude/context/memory/issues.md - 決定事項 ->
.claude/context/memory/decisions.md
中断を前提にしてください。メモリーに記録されていなければ、起きていないものとして扱います。
コメント
Markdown 対応