# 機能設計書 53-JUnitレポート

## 概要

本ドキュメントは、BunテストランナーにおけるJUnit形式レポート出力機能の設計仕様を記述する。

### 本機能の処理概要

JUnitレポート機能は、テスト実行結果をJUnit XML形式で出力する。CI/CDパイプラインとの連携、テスト結果の可視化ツール（Jenkins、GitLab CI、GitHub Actions等）でのレポート表示を可能にする。

**業務上の目的・背景**：CI/CDツールの多くはJUnit XML形式のテストレポートを標準的にサポートしており、この形式で出力することで既存のインフラストラクチャとシームレスに連携できる。テスト結果の集計、履歴管理、可視化を容易にする。

**機能の利用シーン**：CI/CDパイプラインでのテスト結果レポート生成、Jenkins/GitLab CI/GitHub Actionsでのテスト結果表示、テスト結果の外部ツールへのインポート。

**主要な処理内容**：
1. `--junit`オプションの解析と出力ファイルパスの設定
2. テストスイート（describe）の階層構造追跡
3. テストケース（test）の実行結果記録
4. XMLエスケープ処理
5. JUnit XML形式でのファイル出力

**関連システム・外部連携**：CI/CDツール（Jenkins、GitLab CI、GitHub Actions等）、テスト結果可視化ツール。

**権限による制御**：特になし。全ユーザーが利用可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 2 | test | 主画面 | `--junit`オプションによるJUnitレポート出力 |

## 機能種別

レポート出力

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| --junit | 文字列 | No | JUnitレポート出力ファイルパス | 有効なファイルパス |

### 入力データソース

- テスト実行結果（各テストケースの成功/失敗/スキップ）
- テストスイート（describe）の階層構造
- テストケースのメタデータ（名前、行番号、実行時間）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| testsuite | XML要素 | テストスイート（describeブロック単位） |
| testcase | XML要素 | 個別テストケース |
| failure | XML要素 | テスト失敗情報 |
| skipped | XML要素 | スキップされたテスト |
| properties | XML要素 | CI情報等のプロパティ |

### 出力先

- 指定されたファイルパス（--junitオプション値）

### JUnit XML出力形式

```xml
<?xml version="1.0" encoding="UTF-8"?>
<testsuites name="bun test" tests="N" assertions="N" failures="N" skipped="N" time="N">
  <testsuite name="ファイルパス" file="ファイルパス" tests="N" ...>
    <properties>
      <property name="ci" value="CI URL" />
      <property name="commit" value="コミットSHA" />
    </properties>
    <testcase name="テスト名" classname="スイート名" time="N" file="ファイル" line="N" assertions="N" />
    <testcase name="失敗テスト" ...>
      <failure type="AssertionError" />
    </testcase>
  </testsuite>
</testsuites>
```

## 処理フロー

### 処理シーケンス

```
1. テストコマンド実行時に--junitオプション解析
   └─ Arguments.zigでオプションをパース
2. JunitReporterの初期化
   └─ JunitReporter.init関数
3. ファイルテストスイート開始時
   └─ beginTestSuite関数でtestsuite要素開始
4. describeブロック開始時
   └─ beginTestSuiteWithLine関数でネストしたtestsuite開始
5. テストケース実行結果記録
   └─ writeTestCase関数でtestcase要素出力
6. テストスイート終了時
   └─ endTestSuite関数でメトリクス計算とtestsuite要素閉じ
7. 全テスト終了後
   └─ writeToFile関数でファイル出力
```

### フローチャート

```mermaid
flowchart TD
    A[テスト開始] --> B{--junit指定?}
    B -->|No| C[レポートなし]
    B -->|Yes| D[JunitReporter初期化]
    D --> E[XMLヘッダー出力]
    E --> F[ファイルtestsuite開始]
    F --> G{describe?}
    G -->|Yes| H[ネストtestsuite開始]
    G -->|No| I[テストケース実行]
    H --> I
    I --> J[writeTestCase]
    J --> K{結果種別}
    K -->|pass| L[testcase出力]
    K -->|fail| M[testcase + failure出力]
    K -->|skip/todo| N[testcase + skipped出力]
    L --> O{次のテスト?}
    M --> O
    N --> O
    O -->|Yes| G
    O -->|No| P[endTestSuite]
    P --> Q[ファイル出力]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-53-1 | XMLエスケープ | &, <, >, ", ' を適切にエスケープ | 全テキスト出力時 |
| BR-53-2 | 制御文字エスケープ | 0x00-0x1Fの制御文字を&#N;形式でエスケープ | 全テキスト出力時 |
| BR-53-3 | CI情報プロパティ | GitHub/GitLab CI環境変数からCI情報を取得 | ファイルスイート開始時 |
| BR-53-4 | メトリクス集計 | tests, assertions, failures, skippedを親スイートに集計 | スイート終了時 |

### 計算ロジック

```
経過時間（秒） = elapsed_ns / 1,000,000,000
失敗判定 = status == fail || fail_because_* のいずれか
```

## データベース操作仕様

本機能はデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | FileWriteError | ファイル書き込み失敗 | エラーログ出力、処理継続 |
| - | OutOfMemory | メモリ不足 | エラーログ出力 |

### リトライ仕様

リトライは行わない。

## トランザクション仕様

該当なし（データベース操作なし）。

## パフォーマンス要件

- XMLバッファリングによりメモリ効率を維持
- 大量テストケース（10,000件以上）でも安定動作

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

- テストファイルパスがレポートに含まれるため、公開環境での出力に注意
- CI情報（コミットSHA、CI URL）が含まれる場合がある

## 備考

- ホスト名はPOSIX環境のみで取得可能（Windows未対応）
- タイムスタンプフィールドは現在未実装（TODOコメント参照）

---

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

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

### 推奨読解順序

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

まず、JUnitレポーターの基本構造を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | test_command.zig | `src/cli/test_command.zig` | JunitReporter構造体、SuiteInfo、Metrics |

**読解のコツ**: JunitReporterはスイートのスタック（suite_stack）でネスト構造を管理している点に注目。

**主要処理フロー**:
- **73-86行目**: JunitReporter構造体の定義。contents（XMLバッファ）、suite_stack（スイートスタック）
- **115-127行目**: SuiteInfo構造体。テストスイートのメタデータと開始オフセット
- **129-142行目**: Metrics構造体。tests, assertions, failures, skipped, elapsed_time

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

テストスイートの開始と終了がどのように処理されるかを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | test_command.zig | `src/cli/test_command.zig` | beginTestSuite、endTestSuite |

**主要処理フロー**:
- **266-329行目**: beginTestSuiteWithLine関数。testsuite要素の開始とスタックへのプッシュ
- **331-370行目**: endTestSuite関数。メトリクス計算とtestsuite要素の終了

#### Step 3: テストケース出力処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | test_command.zig | `src/cli/test_command.zig` | writeTestCase関数 |

**主要処理フロー**:
- **372-500行目**: writeTestCase関数。テスト結果に応じたtestcase要素の出力
- **414-432行目**: pass/fail分岐。失敗時はfailure要素を追加

#### Step 4: XMLエスケープ処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | test_command.zig | `src/cli/test_command.zig` | escapeXml関数 |

**主要処理フロー**:
- **4-41行目**: escapeXml関数。&, <, >, ", 'と制御文字のエスケープ処理

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

```
test_command.zig (テストコマンド実行)
    │
    ├─ JunitReporter.init
    │
    ├─ beginTestSuite (ファイルスイート)
    │      └─ generatePropertiesList (CI情報)
    │
    ├─ beginTestSuiteWithLine (describeブロック)
    │
    ├─ writeTestCase (テストケース)
    │      └─ escapeXml (XMLエスケープ)
    │
    ├─ endTestSuite (スイート終了)
    │      └─ Metrics.add (メトリクス集計)
    │
    └─ writeToFile (ファイル出力)
```

### データフロー図

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

テスト実行開始 ────▶ JunitReporter.init ────────▶ XMLヘッダー
                              │
describe開始 ────────▶ beginTestSuiteWithLine ──▶ <testsuite>開始
                              │
テストケース実行 ───▶ writeTestCase ─────────────▶ <testcase>要素
                              │                      │
                              │                      ├─ pass: 空要素
                              │                      ├─ fail: <failure>
                              │                      └─ skip: <skipped>
                              │
describe終了 ────────▶ endTestSuite ─────────────▶ </testsuite>
                              │
全テスト終了 ────────▶ writeToFile ──────────────▶ XMLファイル
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| test_command.zig | `src/cli/test_command.zig` | ソース | JunitReporter実装の中核 |
| Arguments.zig | `src/cli/Arguments.zig` | ソース | --junitオプション解析 |
| bun_test.zig | `src/bun.js/test/bun_test.zig` | ソース | テスト実行とレポーター呼び出し |
| jest.zig | `src/bun.js/test/jest.zig` | ソース | Jest互換API |
