• #テスト
  • #Vitest
  • #Playwright
  • #カバレッジ
  • #セキュリティ
  • #E2E
  • #CI
開発eurekapuメモ

テスト基盤整備とカバレッジ改善

朝、テストファイルが1つもない状態のリポジトリを開いた。夜、215 tests passed の緑文字がターミナルに並んでいた。8ステップの計画を立て、1ステップずつチェックボックスを埋めていった一日の記録。

計画の立て方

Codexレビューを計画段階で挟んだ。8ステップの計画書をマークダウンで書き、codex exec に投げて致命的な穴がないか確認してから着手した。セッションが切り替わるたびにチェックボックスの進捗を見て、どこまで終わっているかを30秒で把握できた。

Step 1: Composableテスト (102テストパス)

questionIduseQuizHistory のComposableから着手した。UIに依存しない純粋なロジック層なので、最初のステップとして手堅い。

テストランナーはVitest。102ケースが通った時点で、テスト実行環境が正しく動いていることを確認できた。

Step 2: サーバーAPIテスト基盤 (108テストパス)

quiz-history-post.test.ts でサーバーAPIテストのパターンを確立した。

ここで vi.hoisted() を使ったモック注入パターンを固めた。Nitroのサーバーハンドラはモジュールスコープで依存を解決するため、通常の vi.mock() ではタイミングが合わない。vi.hoisted() でモック変数を巻き上げることで、ハンドラが読み込まれる前にモックが差し込まれる。

const mocks = vi.hoisted(() => ({
  getSession: vi.fn(),
  db: { prepare: vi.fn() }
}))

vi.mock('~/server/utils/auth', () => ({ getSession: mocks.getSession }))

このパターンを以降の全サーバーAPIテストで踏襲した。

Step 3: 全サーバーAPIハンドラのテスト (160テストパス)

12ファイル、58ケースを一気に書いた。Stripe webhookのテストも含む。webhookはペイロードと署名ヘッダーの組み合わせで分岐が多いが、正常系・署名不正・イベント種別ごとのケースを網羅した。

Step 4: セキュリティ修正3件 (168テストパス)

テストを書く過程で、テスト対象のコード自体に穴が見つかった。

  1. history-migrate.post: リクエストボディのバリデーションが甘く、不正なデータを受け付けていた。Zodスキーマを追加
  2. webhook署名検証: 検証ロジックをスキップできるパスが存在していた。条件分岐を修正
  3. admin-usersのSQLインジェクション対策: ユーザー入力がプレースホルダーを経由せずクエリに渡っていた。パラメータバインドに変更

テストがなければ、これらは「動いているから大丈夫」で見過ごされていた。テストを書く行為自体がコードレビューとして機能した。

Step 5: カバレッジ計測・改善 (176テストパス)

v8プロバイダーでカバレッジを計測した。checkout.post のブランチカバレッジが低かったので、エラーハンドリングのパスを中心にテストを追加した。

カバレッジの数字を上げること自体は目的ではないが、「このブランチ通ってないぞ」という指摘を機械的にもらえるのは助かる。

Step 6: E2Eテスト - Playwright (62テストパス)

Playwrightでブラウザを動かすE2Eテストを62ケース書いた。

2つのUI要素で手が止まった。ログインプロンプトの「あとで」ボタンと、クイズ最終問題の「結果を見る」ボタン。どちらもテスト用のセレクタが付いておらず、テキストマッチで拾う必要があった。getByText('あとで')getByText('結果を見る') で対応したが、文言が変わったら壊れる。将来的には data-testid を付けたい。

Step 7: ベンチマーク

vitest bench で3ファイルのベンチマークを作成した。パフォーマンス回帰を検知するための基準値を記録しておく目的。現時点では手動実行だが、CIに組み込む余地を残している。

Step 8: コードレビュー選定項目 (215テスト全パス)

最後にコードレビューで出た改善項目を2件実施した。

  • batch API化: 個別のAPIコールをバッチリクエストにまとめて、リクエスト数を削減
  • ヘルスチェック深化: /api/health がDBへの疎通確認まで行うように拡張

215テストが全て緑になった状態でこのステップを終えた。

振り返り

朝の時点で「テストゼロ」だったリポジトリに、夜には215のテストが走っている。数字の変化よりも、Step 4でセキュリティの穴が3件見つかったことが一番の収穫だった。テストを書く手が、そのままコードレビューの目になっていた。

セッション切り替えのたびにチェックボックスを確認する運用も機能した。8ステップを一気に書き切るのではなく、1ステップごとに区切ってテスト数の増加を確認していく進め方が、長丁場でもペースを保てた理由だと思う。