Skip to content
Development
Command

/rev-specs

既存のコードベースから包括的なテストケースと仕様書を逆生成します。実装されたビジネスロジック、API動作、UI コンポーネントの動作を分析し、不足しているテストケースを特定・生成し、仕様書として文書化します。

BOOST
From plugin
tsumiki
97443 skills43 commands
Install
> /plugin marketplace add classmethod/tsumiki
> /plugin install tsumiki@tsumiki

How it fires

How this command gets triggered: by you, by Claude, or both.

  • Fires itselfClaude auto-loads it when your prompt matches the work.
  • You can call itInvoke it directly when you want it.
  • Slash command/rev-specs

Context preview

What this command does when you run it.

既存のコードベースから包括的なテストケースと仕様書を逆生成します。実装されたビジネスロジック、API動作、UI コンポーネントの動作を分析し、不足しているテストケースを特定・生成し、仕様書として文書化します。

Command definition

rev-specs.md
description: 既存のコードベースから包括的なテストケースと仕様書を逆生成します。実装されたビジネスロジック、API動作、UI コンポーネントの動作を分析し、不足しているテストケースを特定・生成し、仕様書として文書化します。

rev-specs

目的

既存のコードベースから包括的なテストケースと仕様書を逆生成する。実装されたビジネスロジック、API動作、UI コンポーネントの動作を分析し、不足しているテストケースを特定・生成し、仕様書として文書化する。

前提条件

  • 分析対象のコードベースが存在する
  • `docs/spec/{要件名}/` ディレクトリが存在する(なければ作成)
  • 可能であれば事前に `/tsumiki:rev-requirements`, `/tsumiki:rev-design` を実行済み

実行内容

1. **既存テストの分析**

  • 単体テスト(Unit Test)の実装状況確認
  • 統合テスト(Integration Test)の実装状況確認
  • E2Eテスト(End-to-End Test)の実装状況確認
  • テストカバレッジの測定

2. **実装コードからテストケースの逆生成**

  • 関数・メソッドの引数・戻り値からのテストケース生成
  • 条件分岐からの境界値テスト生成
  • エラーハンドリングからの異常系テスト生成
  • データベース操作からのデータテスト生成

3. **API仕様からテストケースの生成**

  • 各エンドポイントの正常系テスト
  • 認証・認可テスト
  • バリデーションエラーテスト
  • HTTPステータスコードテスト

4. **UI コンポーネントからテストケースの生成**

  • コンポーネントレンダリングテスト
  • ユーザーインタラクションテスト
  • 状態変更テスト
  • プロパティ変更テスト

5. **パフォーマンス・セキュリティテストケースの生成**

  • 負荷テストシナリオ
  • セキュリティ脆弱性テスト
  • レスポンス時間テスト

6. **テスト仕様書の生成**

  • テスト計画書
  • テストケース一覧
  • テスト環境仕様
  • テスト手順書

7. **ファイルの作成**

  • `docs/spec/{要件名}/test-specs.md` - テスト仕様書
  • `docs/spec/{要件名}/test-cases.md` - テストケース一覧
  • `docs/spec/{要件名}/tests/` - 生成されたテストコード

出力フォーマット例

test-specs.md

# {要件名} テスト仕様書(逆生成)

## 分析概要

**分析日時**: {実行日時}
**対象コードベース**: {パス}
**テストカバレッジ**: {現在のカバレッジ}%
**生成テストケース数**: {生成数}個
**実装推奨テスト数**: {推奨数}個

## 現在のテスト実装状況

### テストフレームワーク
- **単体テスト**: {Jest/Vitest/pytest等}
- **統合テスト**: {Supertest/TestContainers等}
- **E2Eテスト**: {Cypress/Playwright等}
- **コードカバレッジ**: {istanbul/c8等}

### テストカバレッジ詳細

| ファイル/ディレクトリ | 行カバレッジ | 分岐カバレッジ | 関数カバレッジ |
|---------------------|-------------|-------------|-------------|
| src/auth/ | 85% | 75% | 90% |
| src/users/ | 60% | 45% | 70% |
| src/components/ | 40% | 30% | 50% |
| **全体** | **65%** | **55%** | **75%** |

### テストカテゴリ別実装状況

#### 単体テスト
- [x] **認証サービス**: auth.service.spec.ts
- [x] **ユーザーサービス**: user.service.spec.ts
- [ ] **データ変換ユーティリティ**: 未実装
- [ ] **バリデーションヘルパー**: 未実装

#### 統合テスト
- [x] **認証API**: auth.controller.spec.ts
- [ ] **ユーザー管理API**: 未実装
- [ ] **データベース操作**: 未実装

#### E2Eテスト
- [ ] **ユーザーログインフロー**: 未実装
- [ ] **データ操作フロー**: 未実装
- [ ] **エラーハンドリング**: 未実装

## 生成されたテストケース

### API テストケース

#### POST /auth/login - ログイン認証

**正常系テスト**
```typescript
describe('POST /auth/login', () => {
  it('有効な認証情報でログイン成功', async () => {
    const response = await request(app)
      .post('/auth/login')
      .send({
        email: 'test@example.com',
        password: 'password123'
      });
    
    expect(response.status).toBe(200);
    expect(response.body.success).toBe(true);
    expect(response.body.data.token).toBeDefined();
    expect(response.body.data.user.email).toBe('test@example.com');
  });

  it('JWTトークンが正しい形式で返される', async () => {
    const response = await request(app)
      .post('/auth/login')
      .send(validCredentials);
    
    const token = response.body.data.token;
    expect(token).toMatch(/^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+$/);
  });
});

**異常系テスト**

describe('POST /auth/login - 異常系', () => {
  it('無効なメールアドレスでエラー', async () => {
    const response = await request(app)
      .post('/auth/login')
      .send({
        email: 'invalid-email',
        password: 'password123'
      });
    
    expect(response.status).toBe(400);
    expect(response.body.success).toBe(false);
    expect(response.body.error.code).toBe('VALIDATION_ERROR');
  });

  it('存在しないユーザーでエラー', async () => {
    const response = await request(app)
      .post('/auth/login')
      .send({
        email: 'nonexistent@example.com',
        password: 'password123'
      });
    
    expect(response.status).toBe(401);
    expect(response.body.error.code).toBe('INVALID_CREDENTIALS');
  });

  it('パスワード間違いでエラー', async () => {
    const response = await request(app)
      .post('/auth/login')
      .send({
        email: 'test@example.com',
        password: 'wrongpassword'
      });
    
    expect(response.status).toBe(401);
    expect(response.body.error.code).toBe('INVALID_CREDENTIALS');
  });
});

**境界値テスト**

describe('POST /auth/login - 境界値', () => {
  it('最小文字数パスワードでテスト', async () => {
    // 8文字(最小要件)
    const response = await request(app)
      .post('/auth/login')
      .send({
        email: 'test@example.com',
        password: '12345678'
      });
    
    expect(response.status).toBe(200);
  });

  it('最大文字数メールアドレスでテスト', async () => {
    // 255文字(最大要件)
    const longEmail = 'a'.repeat(243) + '@example.com';
    const response = await request(app)
      .post('/auth/login')
      .send({
        email: longEmail,
        password: 'password123'
      });
    
    expect(response.status).toBe(400);
  });
});

UIコンポーネントテストケース

LoginForm コンポーネント

**レンダリングテスト**

import { render, screen } from '@testing-library/react';
import { LoginForm } from './LoginForm';

describe('LoginForm', () => {
  it('必要な要素が表示される', () => {
    render(<LoginForm onSubmit={jest.fn()} />);
    
    expect(screen.getByLabelText('メールアドレス')).toBeInTheDocument();
    expect(screen.getByLabelText('パスワード')).toBeInTheDocument();
    expect(screen.getByRole('button', { name: 'ログイン' })).toBeInTheDocument();
  });

  it('初期状態でエラーメッセージが非表示', () => {
    render(<LoginForm onSubmit={jest.fn()} />);
    
    expect(screen.queryByText(/エラー/)).not.toBeInTheDocument();
  });
});

**ユーザーインタラクションテスト**

import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

describe('LoginForm - ユーザーインタラクション', () => {
  it('フォーム送信時にonSubmitが呼ばれる', async () => {
    const mockSubmit = jest.fn();
    render(<LoginForm onSubmit={mockSubmit} />);
    
    await userEvent.type(screen.getByLabelText('メールアドレス'), 'test@example.com');
    await userEvent.type(screen.getByLabelText('パスワード'), 'password123');
    await userEvent.click(screen.getByRole('button', { name: 'ログイン' }));
    
    expect(mockSubmit).toHaveBeenCalledWith({
      email: 'test@example.com',
Read more
Ships withtsumiki

TsumikiはAI駆動開発のためのフレームワークです。要件定義から実装まで、AIを活用した効率的な開発プロセスを提供します。 基本的にClaude Codeをサポートしますが、それ以外のツールでも使用できます。Claude Code以外のツールでtsumikiを使用する を参照してください。

Get the whole plugin

Other commands on tsumiki.

auto-debug
Command

auto-debug

テストエラーを解消するための自動デバッグプロセス。全テストケースの確認からエラー原因の調査、修正まで段階的に実行し、テストケースの成功率向上を目指します。

build-fix
Command

build-fix

ビルドエラー(コンパイルエラー、型エラー、依存パッケージ未解決)を自動的に分析・修正します。auto-debugから委譲される他、ユーザが直接呼び出すことも可能です。