adr-rubber-duck
ADR(Architecture Decision Record)の壁打ち相手としてヒアリングを通じて意思決定を整理し、ADRドラフトを作成する
既存のコードベースから包括的なテストケースと仕様書を逆生成します。実装されたビジネスロジック、API動作、UI コンポーネントの動作を分析し、不足しているテストケースを特定・生成し、仕様書として文書化します。
> /plugin marketplace add classmethod/tsumiki > /plugin install tsumiki@tsumiki
How it fires
How this command gets triggered: by you, by Claude, or both.
/rev-specsContext preview
What this command does when you run it.
既存のコードベースから包括的なテストケースと仕様書を逆生成します。実装されたビジネスロジック、API動作、UI コンポーネントの動作を分析し、不足しているテストケースを特定・生成し、仕様書として文書化します。
description: 既存のコードベースから包括的なテストケースと仕様書を逆生成します。実装されたビジネスロジック、API動作、UI コンポーネントの動作を分析し、不足しているテストケースを特定・生成し、仕様書として文書化します。
既存のコードベースから包括的なテストケースと仕様書を逆生成する。実装されたビジネスロジック、API動作、UI コンポーネントの動作を分析し、不足しているテストケースを特定・生成し、仕様書として文書化する。
1. **既存テストの分析**
2. **実装コードからテストケースの逆生成**
3. **API仕様からテストケースの生成**
4. **UI コンポーネントからテストケースの生成**
5. **パフォーマンス・セキュリティテストケースの生成**
6. **テスト仕様書の生成**
7. **ファイルの作成**
# {要件名} テスト仕様書(逆生成)
## 分析概要
**分析日時**: {実行日時}
**対象コードベース**: {パス}
**テストカバレッジ**: {現在のカバレッジ}%
**生成テストケース数**: {生成数}個
**実装推奨テスト数**: {推奨数}個
## 現在のテスト実装状況
### テストフレームワーク
- **単体テスト**: {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);
});
});**レンダリングテスト**
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',TsumikiはAI駆動開発のためのフレームワークです。要件定義から実装まで、AIを活用した効率的な開発プロセスを提供します。 基本的にClaude Codeをサポートしますが、それ以外のツールでも使用できます。Claude Code以外のツールでtsumikiを使用する を参照してください。
Repo: classmethod/tsumiki
ADR(Architecture Decision Record)の壁打ち相手としてヒアリングを通じて意思決定を整理し、ADRドラフトを作成する
テストエラーを解消するための自動デバッグプロセス。全テストケースの確認からエラー原因の調査、修正まで段階的に実行し、テストケースの成功率向上を目指します。
ビルドエラー(コンパイルエラー、型エラー、依存パッケージ未解決)を自動的に分析・修正します。auto-debugから委譲される他、ユーザが直接呼び出すことも可能です。
システムの各レイヤーにおける包括的なエッジケース・エラー状態を詳細に分析し、見落としがちな異常系シナリオを洗い出します