test-coverage-improver について
Test Coverage Improverは、テストの不足箇所を見つけてテストを追加し、カバレッジを高めるスキルです。レポート用コマンド、テスト例、分岐や境界条件のチェックリストを提供します。
主な機能
- 01カバレッジレポートの生成
- 02テスト不足箇所の優先順位付け
- 03単体テストと非同期テストの例
- 04モックとコンポーネントテストの例
- 05分岐と境界条件のチェックリスト
活用シーン
- 01未テストの重要なコード経路の特定
- 02エラーハンドラーや境界条件のテスト追加
- 03JestまたはVitestプロジェクトのカバレッジ改善
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ onewave-ai/ claude-skills --skill test-coverage-improverインストール後、Claude Code で/test-coverage-improverを入力して読み込まれたか確認します。
詳細
テストカバレッジの改善
手順
テストカバレッジを改善する際は、次の手順に従います。
- カバレッジレポートを実行して、カバレッジの不足箇所を特定します
- 重要度や複雑さを基に優先順位を付けます
- カバレッジされていないコードのテストを作成します
- カバレッジが改善されたことを確認します
カバレッジレポートの生成
# Jest
npx jest --coverage
# Vitest
npx vitest --coverage
# NYC (Istanbul) for any test runner
npx nyc npm test
# View HTML report
open coverage/lcov-report/index.html
カバレッジ目標
| 種類 | 最低 | 良好 | 優秀 |
|---|---|---|---|
| 行 | 70% | 80% | 90%+ |
| 分岐 | 60% | 75% | 85%+ |
| 関数 | 70% | 80% | 90%+ |
| 文 | 70% | 80% | 90%+ |
テストテンプレート
ユニットテスト(Jest/Vitest)
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { calculateTotal, formatCurrency } from './utils';
describe('calculateTotal', () => {
it('should sum all item prices', () => {
const items = [
{ price: 10, quantity: 2 },
{ price: 5, quantity: 1 },
];
expect(calculateTotal(items)).toBe(25);
});
it('should return 0 for empty array', () => {
expect(calculateTotal([])).toBe(0);
});
it('should handle decimal prices', () => {
const items = [{ price: 10.99, quantity: 1 }];
expect(calculateTotal(items)).toBeCloseTo(10.99);
});
});
非同期関数のテスト
describe('fetchUser', () => {
it('should return user data', async () => {
const user = await fetchUser(1);
expect(user).toEqual({
id: 1,
name: expect.any(String),
email: expect.stringContaining('@'),
});
});
it('should throw for non-existent user', async () => {
await expect(fetchUser(999)).rejects.toThrow('User not found');
});
});
依存関係のモック
import { vi } from 'vitest';
import { sendEmail } from './email';
import { createUser } from './user';
vi.mock('./email', () => ({
sendEmail: vi.fn().mockResolvedValue({ success: true }),
}));
describe('createUser', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('should send welcome email after creating user', async () => {
await createUser({ name: 'John', email: '[email protected]' });
expect(sendEmail).toHaveBeenCalledWith({
to: '[email protected]',
template: 'welcome',
});
});
});
React コンポーネントのテスト
import { render, screen, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Button } from './Button';
describe('Button', () => {
it('should render children', () => {
render(<Button>Click me</Button>);
expect(screen.getByText('Click me')).toBeInTheDocument();
});
it('should call onClick when clicked', async () => {
const handleClick = vi.fn();
render(<Button onClick={handleClick}>Click</Button>);
await userEvent.click(screen.getByRole('button'));
expect(handleClick).toHaveBeenCalledTimes(1);
});
it('should be disabled when loading', () => {
render(<Button isLoading>Submit</Button>);
expect(screen.getByRole('button')).toBeDisabled();
});
});
API ルートのテスト
import { createMocks } from 'node-mocks-http';
import handler from './api/users';
describe('GET /api/users', () => {
it('should return users list', async () => {
const { req, res } = createMocks({ method: 'GET' });
await handler(req, res);
expect(res._getStatusCode()).toBe(200);
expect(JSON.parse(res._getData())).toHaveProperty('users');
});
});
分岐カバレッジのチェックリスト
テストが次の項目をカバーしていることを確認します。
- If/else の分岐
- 三項演算子
- Switch のケース(default を含む)
- Try/catch ブロック
- 早期リターン
- Nullish coalescing(
??) - オプショナルチェーンの結果(
?.) - ループ条件(0 回、1 回、複数回の反復)
カバレッジの設定
// vitest.config.ts
export default {
test: {
coverage: {
provider: 'v8',
reporter: ['text', 'html', 'lcov'],
exclude: [
'node_modules/',
'**/*.d.ts',
'**/*.test.ts',
'**/types/',
],
thresholds: {
lines: 80,
branches: 75,
functions: 80,
statements: 80,
},
},
},
};
テストの優先順位
- 重要な処理:認証、決済、データ変更
- 複雑なロジック:アルゴリズム、状態機械、計算
- エラーハンドラー:Catch ブロック、エラーバウンダリー
- エッジケース:空の配列、null 値、境界値
- 統合ポイント:API 呼び出し、データベースクエリ
コメント
Markdown 対応