メインコンテンツまでスキップ

CI/CDにおけるテスト戦略

このドキュメントの目的

CI/CDパイプラインにおけるテスト戦略を理解し、品質と開発速度のバランスを取ったテスト設計ができるようになることが目標です。

IDサービスを題材にした具体例を使用しますが、設計原則自体はあらゆるSaaSに共通して適用できます。


テストピラミッド

ピラミッドの構造

テストピラミッドは、テストの種類と量の理想的なバランスを示すモデルです。

テストピラミッド:

/\
/ \ E2Eテスト
/ E2E\ ・少数
/______\ ・遅い・高コスト
/ \ ・実際のユーザーシナリオ
/ 統合テスト \
/____________\ 統合テスト
/ \ ・中程度の数
/ ユニットテスト \ ・中程度の速度
/__________________\ ・コンポーネント間連携

ユニットテスト
・大量
・高速・低コスト
・個別の関数・クラス
テスト種別比率(目安)実行時間フィードバック速度信頼性
ユニットテスト70%数秒〜数分即座高い
統合テスト20%数分数分中程度
E2Eテスト10%数十分遅い低い(Flaky)

ピラミッドが崩れるケース

逆ピラミッド(アンチパターン):     アイスクリームコーン(アンチパターン):

________________ ________
/ \ / 手動 \
/ E2Eテストが大量 \ / テスト \
\ / /____________\
\ 統合テスト少数 / / E2E \
\______________/ / 大量 \
/ ユニット \ /________________\
/ テスト少数 \ / 統合テスト少数 \
\_____________/ \__________________/
/ ユニットテスト \
/ 少数 \
\___________________/

問題点:

  • E2Eテストが多すぎると実行時間が長くなり、フィードバックが遅延
  • 手動テストに依存するとリリース速度が低下
  • ユニットテストが少ないとバグの特定が困難

CIで実行するテストの種類

テスト実行の順序

CIパイプラインでは、コストの低いテストから順に実行します。

高速・低コスト                                    低速・高コスト
◀─────────────────────────────────────────────────────────▶

┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ 静的解析 │─▶│ ユニット │─▶│ 統合 │─▶│ E2E │─▶│セキュリティ│
│ │ │ テスト │ │ テスト │ │ テスト │ │ スキャン │
│ │ │ │ │ │ │ │ │ │
│ Spotless │ │ JUnit │ │ DB接続 │ │ HTTP │ │ Trivy │
│ SpotBugs │ │ Mockito │ │ API呼出 │ │ シナリオ │ │ OWASP │
│ │ │ │ │ │ │ │ │ Dependabot│
└──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘
数秒 数分 数分 数十分 数分

各テストの詳細

静的解析

コードを実行せずに品質を検証します。

ツール検出内容
Spotlessフォーマット違反
SpotBugs潜在的バグパターン
Checkstyleコーディング規約違反
Dependency Check脆弱な依存ライブラリ

ユニットテスト

個々のクラス・メソッドの動作を検証します。外部依存はモック化します。

IDサービスの場合:

  • トークンの署名検証ロジック
  • 認可リクエストのバリデーション
  • スコープのマッチングロジック

統合テスト

複数のコンポーネントを組み合わせた動作を検証します。

IDサービスの場合:

  • データベースへの永続化と取得
  • 外部IdPとの連携(テスト用モック)
  • 設定の読み込みと反映

E2Eテスト

実際のユーザーシナリオに沿ったエンドツーエンドの検証を行います。

IDサービスの場合:

  • 認可コードフロー全体(認可リクエスト→認証→同意→トークン取得)
  • CIBAフロー(認証リクエスト→バックチャネル認証→トークン取得)
  • マルチテナント環境でのテナント分離

セキュリティスキャン

コードと依存ライブラリの脆弱性を検出します。

スキャン種別対象ツール例
依存ライブラリスキャンpom.xml, build.gradleDependabot, Snyk
コンテナイメージスキャンDocker ImageTrivy, Grype
SAST(静的アプリケーションセキュリティテスト)ソースコードSonarQube, CodeQL
シークレットスキャンリポジトリ全体GitLeaks, TruffleHog

テスト実行の最適化

並列化

テストを並列実行することで、全体の実行時間を短縮します。

直列実行:
┌────────────────────────────────────────────────┐
│ Test1 → Test2 → Test3 → Test4 → Test5 → Test6 │ 合計: 30分
└────────────────────────────────────────────────┘

並列実行(3ワーカー):
┌──────────────────┐
│ Test1 → Test4 │ ワーカー1
├──────────────────┤
│ Test2 → Test5 │ ワーカー2 合計: 10分
├──────────────────┤
│ Test3 → Test6 │ ワーカー3
└──────────────────┘

並列化の方式:

方式説明適用場面
テストファイル分割テストファイル単位で分散ユニットテスト
テストスイート分割テストスイート単位で分散統合テスト
マトリクスビルドDB種別等の組み合わせを並列環境互換性テスト

差分テスト(影響範囲テスト)

変更されたコードに関連するテストのみを実行し、CIの実行時間を短縮します。

変更なし        変更あり
┌─────────┐ ┌─────────┐
│ Module A │ │ Module B │ ← コード変更
└─────────┘ └─────────┘


┌─────────┐
│ Module B │ ← このモジュールのテストのみ実行
│ のテスト │
└─────────┘

注意点: 差分テストはPull Request時の高速フィードバックに有効ですが、mainブランチへのマージ時には全テストを実行すべきです。

Flaky Tests対策

Flaky Test = 同じコードなのに成功・失敗が不安定なテスト

原因対策
タイミング依存明示的な待機条件を使用(sleep禁止)
テスト間の依存テストの独立性を確保(共有状態を排除)
外部サービス依存モック / テストコンテナの使用
リソース競合テスト用リソースの分離(ポート、DB名)
ランダム性シード値の固定、決定的なテストデータ

Flaky Testへの対応方針:

Flaky Test検出

├── 即座に修正できる → 修正する

├── 修正に時間がかかる → @Quarantine タグで隔離し、
│ CIの必須チェックから除外

└── 根本原因が不明 → テスト設計を見直す

テスト環境の管理

テスト用データベース

方式説明利点欠点
インメモリDBH2等でテスト実行高速、セットアップ不要本番DBとの互換性の差異
テストコンテナDockerでDB起動本番同等の環境起動に時間がかかる
共有テストDBチーム共有のDBセットアップ不要テスト間の干渉、並列実行困難

IDサービスの場合: PostgreSQLとMySQLの両方をサポートするため、テストコンテナ(Testcontainers)を使用して本番同等の環境でテストを実行します。

テストデータ管理

テストデータの管理方針:

┌──────────────┐
│ テストデータ │
│ 生成パターン │
└──────┬───────┘

┌────┼────────────────┐
│ │ │
▼ ▼ ▼
Fixture Factory Faker
固定データ プログラムで ランダム
(JSON等) 生成 データ

確定的 柔軟 エッジケース
可読性高 再利用性高 発見に有効

品質ゲート

品質ゲートとは

品質ゲートは、パイプラインの各ステージで「通過条件」を定義し、基準を満たさない場合にパイプラインを停止する仕組みです。

品質ゲートの例:

┌──────────┐ Gate1 ┌──────────┐ Gate2 ┌──────────┐
│ Build │──────────▶│ Test │──────────▶│ Deploy │
└──────────┘ └──────────┘ └──────────┘
│ │
▼ ▼
・コンパイル成功 ・テスト全件成功
・静的解析 Pass ・カバレッジ >= 80%
・セキュリティ ・セキュリティ
スキャン Pass スキャン Pass

品質ゲートの設計

ゲート条件閾値(例)
ビルドコンパイル成功必須
フォーマットSpotless / Prettier Pass必須
静的解析SpotBugs等の指摘ゼロCritical: 0, Warning: 10以下
ユニットテスト全件成功必須
テストカバレッジ行カバレッジ新規コード: 80%以上
統合テスト全件成功必須
セキュリティスキャン脆弱性ゼロCritical/High: 0

カバレッジ閾値の設計

対象閾値理由
新規コード80%以上新しいコードは十分にテストする
既存コード全体下がらないこと既存の品質を維持する
コアモジュール90%以上認証・認可等の重要ロジック

注意点: カバレッジは品質の1指標に過ぎません。カバレッジが高くても、テストの質(アサーションの適切さ、エッジケースの網羅)が低ければ品質は担保できません。

品質ゲートの段階的導入

新規プロジェクトでない場合、品質ゲートは段階的に導入します。

Phase 1: 計測開始(ゲート無効)
↓ 現状の品質レベルを把握
Phase 2: 警告モード
↓ 基準未達を警告するが、ブロックしない
Phase 3: 新規コードのみ適用
↓ 新しいコードに対してのみゲートを有効化
Phase 4: 全コード適用
既存コードを含めてゲートを有効化

次のステップ

CI/CDにおけるテスト戦略を理解しました。

次に読むべきドキュメント

  1. デプロイ戦略 - 安全なリリース手法
  2. パイプライン設計 - テスト戦略をパイプラインに組み込む

最終更新: 2026-03-04 対象: SaaS開発者・QAエンジニア