# 帳票設計書 16-Test Report

## 概要

本ドキュメントは、GitLabにおけるTest Report機能の帳票設計書である。CIパイプラインのテスト実行結果レポートをJSON形式で生成する機能について、出力形式、データ構造、処理フローを定義する。

### 本帳票の処理概要

Test Reportは、CIパイプラインで実行されたテストの結果を比較・分析するレポートである。ベースパイプライン（通常はターゲットブランチ）とヘッドパイプライン（ソースブランチ）のテスト結果を比較し、新規失敗、解決済み、既存失敗などのテストケースを分類して表示する。

**業務上の目的・背景**：Merge Requestのレビュー時に、テストの影響を素早く把握する必要がある。このレポートにより、新たに発生したテスト失敗、解決されたテスト失敗、既存の失敗テストを一目で確認でき、コード変更がテストに与える影響を効率的に評価できる。継続的インテグレーションにおける品質ゲートとして重要な役割を果たす。

**帳票の利用シーン**：Merge Requestの作成・更新時にテスト結果の差分を確認する場合、パイプライン実行後のテスト結果を分析する場合、テスト失敗の履歴を追跡して不安定なテストを特定する場合などで利用される。

**主要な出力内容**：
1. テストステータス（成功/失敗/エラー）
2. テスト結果サマリー（総数、解決数、失敗数、エラー数）
3. テストスイート別の比較結果
4. 新規失敗テストケース一覧
5. 解決済みテストケース一覧
6. 既存失敗テストケース一覧
7. テスト失敗履歴情報

**帳票の出力タイミング**：Merge Request画面のテストレポートウィジェットで表示される。パイプライン完了後にデータが生成される。

**帳票の利用者**：開発者、コードレビュアー、QAエンジニア

## 帳票種別

JSON出力（APIレスポンス）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | Merge Request詳細 | `/:namespace/:project/-/merge_requests/:id` | テストレポートウィジェット表示 |
| - | パイプライン詳細 | `/:namespace/:project/-/pipelines/:id/test_report` | テストタブクリック |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | JSON |
| 用紙サイズ | N/A |
| 向き | N/A |
| ファイル名 | N/A（APIレスポンス） |
| 出力方法 | API経由でJSON返却 |
| 文字コード | UTF-8 |

## 帳票レイアウト

### レイアウト概要

JSONレスポンス構造

```json
{
  "status": "success/failed/parsed/parsing",
  "summary": {
    "total": 100,
    "resolved": 5,
    "failed": 3,
    "errored": 1
  },
  "suites": [
    {
      "name": "TestSuiteName",
      "status": "success/failed",
      "new_failures": [...],
      "resolved_failures": [...],
      "existing_failures": [...],
      "new_errors": [...],
      "resolved_errors": [...],
      "existing_errors": [...]
    }
  ]
}
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | status | 全体ステータス | 計算値 | 文字列 |

### 明細部（summary）

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | total | 総テストケース数 | total_count | 数値 |
| 2 | resolved | 解決済みテスト数 | resolved_count | 数値 |
| 3 | failed | 失敗テスト数 | failed_count | 数値 |
| 4 | errored | エラーテスト数 | error_count | 数値 |

### 明細部（suites配列）

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | name | テストスイート名 | test_suite.name | 文字列 |
| 2 | status | スイートステータス | test_suite.status | 文字列 |
| 3 | new_failures | 新規失敗テスト | suite_comparer.new_failures | 配列 |
| 4 | resolved_failures | 解決済み失敗 | suite_comparer.resolved_failures | 配列 |
| 5 | existing_failures | 既存失敗テスト | suite_comparer.existing_failures | 配列 |

### フッター部

N/A

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| プロジェクトアクセス権 | プロジェクトの読み取り権限 | Yes |
| パイプライン完了 | テストレポートアーティファクト生成済み | Yes |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | テストスイート名 | 昇順 |
| 2 | テストケース名 | 昇順 |

### 改ページ条件

N/A（JSON出力）

## データベース参照仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| ci_pipelines | パイプライン情報 | 主テーブル |
| ci_builds | ビルド情報 | pipeline_id = ci_pipelines.id |
| ci_job_artifacts | テストレポートアーティファクト | job_id = ci_builds.id |
| ci_build_report_results | レポート結果キャッシュ | build_id = ci_builds.id |

### テーブル別参照項目詳細

#### ci_job_artifacts

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| file | テストレポートファイル | file_type = :junit | JUnit XML形式 |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| total_count | 全スイートのテストケース合計 | - | - |
| resolved_count | 解決済みテストの合計 | - | base失敗 → head成功 |
| failed_count | 失敗テストの合計 | - | 新規 + 既存失敗 |
| error_count | エラーテストの合計 | - | 新規 + 既存エラー |
| total_status | 全スイートの最悪ステータス | - | failed > error > success |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[テストレポート要求] --> B{パイプライン実行中?}
    B -->|Yes| C[parsing ステータス返却]
    B -->|No| D[base/headパイプライン取得]
    D --> E[テストレポート取得]
    E --> F{レポート解析中?}
    F -->|Yes| C
    F -->|No| G[TestReportsComparer生成]
    G --> H[TestFailureHistory読み込み]
    H --> I[TestReportsComparerSerializer変換]
    I --> J[JSON返却]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| パース中 | レポート解析中 | status: parsing | 再度リクエスト |
| パースエラー | レポート形式不正 | status: error | テストレポート形式を確認 |
| データなし | テストレポートなし | 空レスポンス | テストジョブ設定を確認 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | テストケース数に依存（〜数千件） |
| 目標出力時間 | 2秒以内 |
| 同時出力数上限 | 特になし |

## セキュリティ考慮事項

- プロジェクトのアクセス権限に基づいてレポートを表示
- テスト結果にはコードの詳細情報が含まれる可能性があるため、権限チェックが必須
- テスト失敗メッセージにセンシティブ情報が含まれる可能性に注意

## 備考

- テストレポートはJUnit XML形式から解析される
- テスト失敗履歴はTestFailureHistoryで管理される
- 大量のテストケースがある場合、レスポンスサイズに注意が必要

---

## コードリーディングガイド

本帳票を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

テストレポートのデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | test_reports_comparer_entity.rb | `app/serializers/test_reports_comparer_entity.rb` | レスポンス構造。total_status, summary, suite_comparersを公開 |

**読解のコツ**: Grape::Entityを使用したシリアライザ。exposeで公開属性を定義。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | compare_test_reports_service.rb | `app/services/ci/compare_test_reports_service.rb` | メインサービス。comparer_class, serializer_class, get_reportを定義 |

**主要処理フロー**:
1. **5-6行目**: comparer_classにTestReportsComparerを指定
2. **9-10行目**: serializer_classにTestReportsComparerSerializerを指定
3. **13-15行目**: get_reportでpipeline.test_reportsを取得
4. **17-22行目**: build_comparerでTestFailureHistoryを読み込み

#### Step 3: ベースサービスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | compare_reports_base_service.rb | `app/services/ci/compare_reports_base_service.rb` | 共通ロジック。execute()がエントリーポイント |

**主要処理フロー**:
- **10-11行目**: base_pipeline実行中ならparsing返却
- **13-14行目**: base/headのレポート取得
- **16行目**: parsing中ならparsing返却
- **18-25行目**: comparerを生成してシリアライズ

#### Step 4: パイプラインのテストレポート取得を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | pipeline.rb | `app/models/ci/pipeline.rb` | test_reportsメソッドの実装（行1332-1338） |

**主要処理フロー**:
- **1332-1338行目**: test_reportsメソッド - TestReportオブジェクトを生成し、各ビルドからテスト結果を収集

### プログラム呼び出し階層図

```
Ci::CompareTestReportsService#execute
    │
    ├─ get_report(base_pipeline)
    │      └─ pipeline.test_reports
    │             └─ build.collect_test_reports!
    │
    ├─ get_report(head_pipeline)
    │      └─ pipeline.test_reports
    │             └─ build.collect_test_reports!
    │
    ├─ build_comparer(base_report, head_report)
    │      ├─ Gitlab::Ci::Reports::TestReportsComparer.new
    │      └─ TestFailureHistory.new.load!
    │
    └─ serializer_class.new.represent(comparer)
           └─ TestReportsComparerSerializer
                  └─ TestReportsComparerEntity
                         └─ TestSuiteComparerEntity (×スイート数)
                                └─ TestCaseEntity
```

### データフロー図

```
[入力]                      [処理]                         [出力]

ci_job_artifacts ─────────▶ Pipeline#test_reports ───▶ TestReport
(JUnit XML)                    │                            │
                               └─ collect_test_reports!     │
                                                            ↓
                                                    TestReportsComparer
base_pipeline ──────────────────────────────────▶        │
                                                         ├─ suite_comparers
head_pipeline ──────────────────────────────────▶        │      ├─ new_failures
                                                         │      ├─ resolved_failures
                                                         │      └─ existing_failures
                                                         │
                                                         └─ TestFailureHistory
                                                                   ↓
                                                    TestReportsComparerSerializer
                                                                   ↓
                                                             JSON レスポンス
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| compare_test_reports_service.rb | `app/services/ci/compare_test_reports_service.rb` | ソース | テストレポート比較サービス |
| compare_reports_base_service.rb | `app/services/ci/compare_reports_base_service.rb` | ソース | ベースサービス |
| test_reports_comparer_serializer.rb | `app/serializers/test_reports_comparer_serializer.rb` | ソース | シリアライザ |
| test_reports_comparer_entity.rb | `app/serializers/test_reports_comparer_entity.rb` | ソース | エンティティ |
| test_suite_comparer_entity.rb | `app/serializers/test_suite_comparer_entity.rb` | ソース | スイートエンティティ |
| pipeline.rb | `app/models/ci/pipeline.rb` | ソース | test_reportsメソッド |
| test_report.rb | `lib/gitlab/ci/reports/test_report.rb` | ソース | テストレポートモデル |
| test_reports_comparer.rb | `lib/gitlab/ci/reports/test_reports_comparer.rb` | ソース | 比較ロジック |
| test_failure_history.rb | `lib/gitlab/ci/reports/test_failure_history.rb` | ソース | 失敗履歴 |
