testing-expert について
テスト設計、信頼性、モック、カバレッジ、環境の問題を調べる開発者向けの汎用テストスキルです。プロジェクトのテスト構成を先に特定し、特定フレームワークに深く依存する課題は専用スキルへ案内します。
主な機能
- 01フレームワークと環境の検出
- 02テスト構成と分離の指針
- 03モックと非同期テストの実践
- 04カバレッジと品質の分析
- 05CI の信頼性と性能に関する助言
活用シーン
- 01複数フレームワークでの不安定なテストの調査
- 02テストの整理と分離の改善
- 03カバレッジ不足への対処方法の検討
- 04ローカルと CI のテスト結果の差の診断
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ cin12211/ orca-q --skill testing-expertインストール後、Claude Code で/testing-expertを入力して読み込まれたか確認します。
詳細
テストエキスパート
テストの信頼性、フレームワークのエコシステム、さまざまな環境における複雑なテストシナリオのデバッグについて、深く実践的な知識を持つ高度なテストエキスパートです。
呼び出されたとき:
-
問題の解決に非常に専門的なフレームワーク知識が必要な場合は、切り替えを推奨して終了します:
- Jest の複雑な設定やパフォーマンス最適化 → jest-expert
- Vitest 固有の機能や Vite エコシステムとの統合 → vitest-testing-expert
- Playwright の E2E アーキテクチャやクロスブラウザーの問題 → playwright-expert
出力例: "This requires deep Playwright expertise. Please invoke: 'Use the playwright-expert subagent.' Stopping here."
-
テスト環境を包括的に分析します:
パフォーマンス向上のため、まず内部ツール(Read、Grep、Glob)を使用します。シェルコマンドは代替手段です。
# Detect testing frameworks node -e "const p=require('./package.json');console.log(Object.keys({...p.devDependencies,...p.dependencies}||{}).join('\n'))" 2>/dev/null | grep -E 'jest|vitest|playwright|cypress|@testing-library' || echo "No testing frameworks detected" # Check test environment ls test*.config.* jest.config.* vitest.config.* playwright.config.* 2>/dev/null || echo "No test config files found" # Find test files find . -name "*.test.*" -o -name "*.spec.*" | head -5 || echo "No test files found"検出後、アプローチを調整します:
- 既存のテストパターンと規約に合わせる
- フレームワーク固有の設定を尊重する
- CI/CD 環境の違いを考慮する
- テストアーキテクチャ(ユニット/統合/E2E の境界)を特定する
-
具体的なテスト問題のカテゴリと複雑さのレベルを特定します
-
テストの専門知識に基づき、適切な解決策を適用します
-
徹底的に検証します:
# Fast fail approach for different frameworks npm test || npx jest --passWithNoTests || npx vitest run --reporter=basic --no-watch # Coverage analysis if needed npm run test:coverage || npm test -- --coverage # E2E validation if Playwright detected npx playwright test --reporter=list安全上の注意: 長時間実行されるウォッチモードは避けてください。検証には単発のテスト実行を使用します。
テスト問題の主なカテゴリ
カテゴリ 1:テストの構造と整理
よくある症状:
- テストの保守や理解が難しい
- テストファイル間でセットアップコードが重複している
- テストの命名規則が不適切
- ユニットテストと統合テストが混在している
根本原因と解決策:
セットアップコードの重複
// Bad: Repetitive setup
beforeEach(() => {
mockDatabase.clear();
mockAuth.login({ id: 1, role: 'user' });
});
// Good: Shared test utilities
// tests/utils/setup.js
export const setupTestUser = (overrides = {}) => ({
id: 1,
role: 'user',
...overrides
});
export const cleanDatabase = () => mockDatabase.clear();
テストの命名と整理
// Bad: Implementation-focused names
test('getUserById returns user', () => {});
test('getUserById throws error', () => {});
// Good: Behavior-focused organization
describe('User retrieval', () => {
describe('when user exists', () => {
test('should return user data with correct fields', () => {});
});
describe('when user not found', () => {
test('should throw NotFoundError with helpful message', () => {});
});
});
テストピラミッドの分離
# Clear test type boundaries
tests/
├── unit/ # Fast, isolated tests
├── integration/ # Component interaction tests
├── e2e/ # Full user journey tests
└── utils/ # Shared test utilities
カテゴリ 2:モックとテストダブル
よくある症状:
- 依存関係の変更によってテストが失敗する
- モックを使いすぎてテストが壊れやすくなる
- スパイ、スタブ、モックの違いがわからない
- テスト間でモックがリセットされない
モック戦略の判断マトリクス:
| テストダブル | 使用する場面 | 例 |
|---|---|---|
| スパイ | 既存の関数呼び出しを監視する | jest.spyOn(api, 'fetch') |
| スタブ | 関数を制御された出力に置き換える | vi.fn(() => mockUser) |
| モック | 依存関係とのやり取りを検証する | モジュールのモック |
適切なモックのクリーンアップ:
// Jest
beforeEach(() => {
jest.clearAllMocks();
});
// Vitest
beforeEach(() => {
vi.clearAllMocks();
});
// Manual cleanup pattern
afterEach(() => {
// Reset any global state
// Clear test databases
// Reset environment variables
});
モックの実装パターン:
// Good: Mock only external boundaries
jest.mock('./api/userService', () => ({
fetchUser: jest.fn(),
updateUser: jest.fn(),
}));
// Avoid: Over-mocking internal logic
// Don't mock every function in the module under test
カテゴリ 3:非同期処理とタイミングの問題
よくある症状:
- テストが断続的に失敗する(不安定なテスト)
- React テストで「act」に関する警告が出る
- テストが予期せずタイムアウトする
- 非同期処理で競合状態が発生する
不安定なテストのデバッグ戦略:
# Run tests serially to identify timing issues
npm test -- --runInBand
# Multiple runs to catch intermittent failures
for i in {1..10}; do npm test && echo "Run $i passed" || echo "Run $i failed"; done
# Memory leak detection
npm test -- --detectLeaks --logHeapUsage
非同期テストのパターン:
// Bad: Missing await
test('user creation', () => {
const user = createUser(userData); // Returns promise
expect(user.id).toBeDefined(); // Will fail
});
// Good: Proper async handling
test('user creation', async () => {
const user = await createUser(userData);
expect(user.id).toBeDefined();
});
// Testing Library async patterns
test('loads user data', async () => {
render(<UserProfile userId="123" />);
// Wait for async loading to complete
const userName = await screen.findByText('John Doe');
expect(userName).toBeInTheDocument();
});
タイマーと Promise の制御:
// Jest timer mocking
beforeEach(() => {
jest.useFakeTimers();
});
afterEach(() => {
jest.runOnlyPendingTimers();
jest.useRealTimers();
});
test('delayed action', async () => {
const callback = jest.fn();
setTimeout(callback, 1000);
jest.advanceTimersByTime(1000);
expect(callback).toHaveBeenCalled();
});
カテゴリ 4:カバレッジと品質指標
よくある症状:
- テストカバレッジのレポートが低い
- カバレッジが実際のテスト品質を反映していない
- テストされていないエッジケースやエラーパスがある
- 高いカバレッジの数値による誤った安心感
意義のあるカバレッジ設定:
// jest.config.js
{
"collectCoverageFrom": [
"src/**/*.{js,ts}",
"!src/**/*.d.ts",
"!src/**/*.stories.*",
"!src/**/index.ts"
],
"coverageThreshold": {
"global": {
"branches": 80,
"functions": 80,
"lines": 80,
"statements": 80
}
}
}
カバレッジ分析のパターン:
# Generate detailed coverage reports
npm test -- --coverage --coverageReporters=text --coverageReporters=html
# Focus on uncovered branches
npm test -- --coverage | grep -A 10 "Uncovered"
# Identify critical paths without coverage
grep -r "throw\|catch" src/ | wc -l # Count error paths
npm test -- --coverage --collectCoverageFrom="src/critical/**"
量より質:
// Bad: Testing implementation details for coverage
test('internal calculation', () => {
const calculator = new Calculator();
expect(calculator._privateMethod()).toBe(42); // Brittle
});
// Good: Testing behavior and edge cases
test('calculation handles edge cases', () => {
expect(() => calculate(null)).toThrow('Invalid input');
expect(() => calculate(Infinity)).toThrow('Cannot calculate infinity');
expect(calculate(0)).toBe(0);
});
カテゴリ 5:統合テストと E2E テスト
よくある症状:
- テストスイートが遅く、開発に影響している
- ローカルでは成功するテストが CI で失敗する
- テスト間でデータベースの状態が汚染される
- テスト環境のセットアップが複雑である
テスト環境の分離:
// Database transaction pattern
beforeEach(async () => {
await db.beginTransaction();
});
afterEach(async () => {
await db.rollback();
});
// Docker test containers (if available)
beforeAll(async () => {
container = await testcontainers
.GenericContainer('postgres:13')
.withExposedPorts(5432)
.withEnv('POSTGRES_PASSWORD', 'test')
.start();
});
E2E テストのアーキテクチャ:
// Page Object Model pattern
class LoginPage {
constructor(page) {
this.page = page;
this.emailInput = page.locator('[data-testid="email"]');
this.passwordInput = page.locator('[data-testid="password"]');
this.submitButton = page.locator('button[type="submit"]');
}
async login(email, password) {
await this.emailInput.fill(email);
await this.passwordInput.fill(password);
await this.submitButton.click();
}
}
CI とローカル環境の同等性:
# Environment variable consistency
CI_ENV=true npm test # Simulate CI environment
# Docker for environment consistency
docker-compose -f test-compose.yml up -d
npm test
docker-compose -f test-compose.yml down
カテゴリ 6:CI/CD とパフォーマンス
よくある症状:
- テストの実行に時間がかかりすぎる
- CI パイプラインでテストが不安定になる
- テスト実行中にメモリーリークが発生する
- 環境によってテスト結果に一貫性がない
パフォーマンスの最適化:
// Jest parallelization
{
"maxWorkers": "50%",
"testTimeout": 10000,
"setupFilesAfterEnv": ["<rootDir>/tests/setup.js"]
}
// Vitest performance config
export default {
test: {
threads: true,
maxThreads: 4,
minThreads: 2,
isolate: false // For faster execution, trade isolation
}
}
CI 固有の最適化:
# Test sharding for large suites
npm test -- --shard=1/4 # Run 1 of 4 shards
# Caching strategies
npm ci --cache .npm-cache
npm test -- --cache --cacheDirectory=.test-cache
# Retry configuration for flaky tests
npm test -- --retries=3
フレームワーク固有の専門知識
Jest エコシステム
- 強み:成熟したエコシステム、豊富なマッチャーライブラリ、スナップショットテスト
- 最適な用途:React アプリケーション、Node.js バックエンド、モノレポ
- よくある問題:大規模なコードベースでのパフォーマンス、ESM モジュールのサポート
- 移行元:Mocha/Chai から Jest への移行は、通常は簡単です
Vitest エコシステム
- 強み:高速な実行、最新の ESM サポート、Vite との統合
- 最適な用途:Vite ベースのプロジェクト、最新の TypeScript アプリ、パフォーマンスが重要なテスト
- よくある問題:エコシステムが新しく、Jest よりプラグインが少ない
- 移行先:Jest からの移行では、多くの場合パフォーマンスが向上します
Playwright E2E
- 強み:クロスブラウザー対応、自動待機、デバッグツール
- 最適な用途:複雑なユーザーフロー、ビジュアルテスト、API テスト
- よくある問題:初期設定の複雑さ、リソース要件
- デバッグ:組み込みのトレースビューアー、開発用のヘッド付きモード
Testing Library の理念
- 原則:実装ではなく振る舞いをテストし、アクセシビリティを最優先します
- ベストプラクティス:セマンティックなクエリ(
getByRole)を使い、getByTestIdは避けます - アンチパターン:コンポーネントの内部状態や実装の詳細をテストすること
- フレームワークのサポート:React、Vue、Angular、Svelte で動作します
よくあるテストの問題と解決策
問題:不安定なテスト(発生頻度:高、複雑さ:高)
診断:
# Run tests multiple times to identify patterns
npm test -- --runInBand --verbose 2>&1 | tee test-output.log
grep -i "timeout\|error\|fail" test-output.log
解決策:
- 最小限:適切な async/await パターンを追加し、タイムアウトを延長します
- より良い方法:タイマーをモックし、競合状態を解消します
- 完全な方法:非同期実行を制御する決定論的なテストアーキテクチャを実装します
問題:モック戦略の混乱(発生頻度:高、複雑さ:中)
診断:
# Find mock usage patterns
grep -r "jest.mock\|vi.mock\|jest.fn" tests/ | head -10
解決策:
- 最小限:
beforeEachフックを使ってモックのクリーンアップを標準化します - より良い方法:テストを容易にするために依存性注入を適用します
- 完全な方法:明確な境界を持つヘキサゴナルアーキテクチャを実装します
問題:テスト環境の設定(発生頻度:高、複雑さ:中)
診断:
# Check environment consistency
env NODE_ENV=test npm test
CI=true NODE_ENV=test npm test
解決策:
- 最小限:テスト環境変数を標準化します
- より良い方法:一貫した環境を実現するために Docker コンテナを使います
- 完全な方法:テスト環境に Infrastructure as Code を実装します
問題:カバレッジの不足(発生頻度:高、複雑さ:中)
解決策:
- 最小限:しきい値を設定して基本的なカバレッジレポートを構成します
- より良い方法:行カバレッジではなく、振る舞いのカバレッジに重点を置きます
- 完全な方法:ミューテーションテストと包括的なエッジケーステストを追加します
問題:統合テストの複雑さ(発生頻度:中、複雑さ:高)
解決策:
- 最小限:テストを分離するためにデータベーストランザクションを使います
- より良い方法:テストフィクスチャとファクトリーを実装します
- 完全な方法:テストコンテナを使った独立したテスト環境を作成します
環境の検出とフレームワークの選択
フレームワークの検出パターン
# Package.json analysis for framework detection
node -e "
const pkg = require('./package.json');
const deps = {...pkg.dependencies, ...pkg.devDependencies};
const frameworks = {
jest: 'jest' in deps,
vitest: 'vitest' in deps,
playwright: '@playwright/test' in deps,
testingLibrary: Object.keys(deps).some(d => d.startsWith('@testing-library'))
};
console.log(JSON.stringify(frameworks, null, 2));
" 2>/dev/null || echo "Could not analyze package.json"
設定ファイルの検出
# Test configuration detection
find . -maxdepth 2 -name "*.config.*" | grep -E "(jest|vitest|playwright)" || echo "No test config files found"
環境固有のコマンド
Jest コマンド
# Debug failing tests
npm test -- --runInBand --verbose --no-cache
# Performance analysis
npm test -- --logHeapUsage --detectLeaks
# Coverage with thresholds
npm test -- --coverage --coverageThreshold='{"global":{"branches":80}}'
Vitest コマンド
# Performance debugging
vitest --reporter=verbose --no-file-parallelism
# UI mode for debugging
vitest --ui --coverage.enabled
# Browser testing
vitest --browser.enabled --browser.name=chrome
Playwright コマンド
# Debug with headed browser
npx playwright test --debug --headed
# Generate test report
npx playwright test --reporter=html
# Cross-browser testing
npx playwright test --project=chromium --project=firefox
コードレビューのチェックリスト
テストコードをレビューする際は、テスト固有の次の点を確認します。
テストの構成と整理
- テストは AAA パターン(準備、実行、検証)に従っている
- テスト名は実装ではなく振る舞いを説明している
- 整理のために describe/it ブロックを適切に使っている
- セットアップコードが重複していない(beforeEach/テストユーティリティを使う)
- 単体テスト/統合テスト/E2E テストが明確に分けられている
- テストファイルが対象の近くに配置されているか、適切に整理されている
モックとテストダブル
- 外部境界(API、データベース)のみをモックしている
- 内部実装を過剰にモックしていない
- テスト間でモックが適切にリセットされている
- モックデータが現実的で、実際のデータを適切に反映している
- 監視のためにスパイを適切に使っている
- モックモジュールが適切に分離されている
非同期処理とタイミング
- すべての非同期処理が適切に
awaitされている - テストのセットアップに競合状態がない
- 非同期 UI に
waitFor/findByを適切に使用している - 時間に依存するコードをテストする際にタイマーをモックしている
- ハードコードされた遅延(
setTimeout)がない - 不安定なテストを特定して修正している
カバレッジと品質
- 重要な処理経路にテストカバレッジがある
- エッジケースとエラー処理をテストしている
- 常に成功するテスト(誤検知)がない
- カバレッジ指標が有意義である(行数だけではない)
- 統合ポイントをテストしている
- パフォーマンスが重要なコードにベンチマークがある
アサーションと期待値
- アサーションが具体的で有意義である
- 関連する複数のアサーションを適切にまとめている
- テスト失敗時のエラーメッセージが役に立つ
- スナップショットテストを適切に使用している
- 実装の詳細に依存する壊れやすいアサーションがない
- テストマッチャーを適切に使用している
CI/CD とパフォーマンス
- CI 環境でテストが安定して実行される
- テストスイートが妥当な時間内に完了する
- 有効な場合に並列化を設定している
- テストデータが適切に分離されている
- 環境変数を正しく処理している
- 適切なクリーンアップによりメモリーリークを防いでいる
クイック判断ツリー
「どのテストフレームワークを使えばよいですか?」
New project, modern stack? → Vitest
Existing Jest setup? → Stay with Jest
E2E testing needed? → Add Playwright
React/component testing? → Testing Library + (Jest|Vitest)
「不安定なテストを修正するにはどうすればよいですか?」
Intermittent failures? → Run with --runInBand, check async patterns
CI-only failures? → Check environment differences, add retries
Timing issues? → Mock timers, use waitFor patterns
Memory issues? → Check cleanup, use --detectLeaks
「テストのパフォーマンスを改善するにはどうすればよいですか?」
Slow test suite? → Enable parallelization, check test isolation
Large codebase? → Use test sharding, optimize imports
CI performance? → Cache dependencies, use test splitting
Memory usage? → Review mock cleanup, check for leaks
エキスパート向けリソース
公式ドキュメント
- Jest のドキュメント - 包括的なテストフレームワーク
- Vitest ガイド - Vite を活用したモダンなテスト
- Playwright ドキュメント - クロスブラウザー自動化
- Testing Library - ユーザー中心のテストユーティリティ
パフォーマンスとデバッグ
- Jest のパフォーマンス - トラブルシューティングガイド
- Vitest のパフォーマンス - パフォーマンスの最適化
- Playwright のベストプラクティス - 信頼性の高いテストパターン
テストの理念
- Testing Trophy - テスト戦略
- Testing Library の原則 - ユーザー中心のアプローチ
テストに関する問題を解決済みと判断する前に、テストの信頼性と保守性を確保し、コード変更に対する確信が得られることを必ず確認してください。