# 機能設計書 105-HeadlessNUnit

## 概要

本ドキュメントは、Avalonia UIフレームワークにおけるNUnitテストフレームワーク統合機能の機能設計書である。NUnitでのUIテストを実行するための基盤を提供する。

### 本機能の処理概要

HeadlessNUnitは、NUnitテストフレームワークとAvalonia Headlessプラットフォームを統合し、NUnitでAvaloniaアプリケーションのUIテストを実行可能にする。NUnitのTestCommand機構を活用し、テストメソッドをAvalonia Dispatcherスレッドで実行する。

**業務上の目的・背景**：NUnitは.NETエコシステムで広く使用されている成熟したテストフレームワークである。HeadlessNUnitにより、既存のNUnitテストプロジェクトでAvalonia UIコンポーネントのテストを追加できる。企業環境でNUnitを標準採用している場合に、移行コストなしでUIテストを導入可能。

**機能の利用シーン**：
- NUnit採用プロジェクトでのAvalonia UIテスト
- 既存NUnitテストスイートへのUIテスト追加
- CIパイプラインでのUIテスト自動実行
- ビューモデルとビューの統合テスト
- UIイベントハンドラーのテスト

**主要な処理内容**：
1. NUnitのIWrapSetUpTearDownインターフェースによるテストコマンドラッピング
2. テストメソッド、SetUp、TearDownのDispatcher上での実行
3. HeadlessUnitTestSessionによるアプリケーションインスタンス管理
4. 非同期テストメソッド（Task/ValueTask）のサポート
5. TestExecutionContextの適切な管理

**関連システム・外部連携**：
- NUnitテストフレームワーク
- Avalonia.Headlessプラットフォーム
- HeadlessUnitTestSession

**権限による制御**：特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | テスト対象ウィンドウ | 仮想画面 | テスト実行時に作成されるHeadlessWindow |

## 機能種別

テストフレームワーク統合 / テスト実行基盤

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| AvaloniaTest属性 | Attribute | Yes | テストメソッドに付与 | - |
| AvaloniaTheory属性 | Attribute | No | パラメータ化テストに付与 | - |
| AvaloniaTestApplication属性 | Attribute | Yes | テストアプリケーションクラスを指定 | アセンブリレベル |

### 入力データソース

- テストメソッドの定義
- テストアプリケーションのAppBuilder設定

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| TestResult | TestResult | テスト実行結果 |
| ResultState | ResultState | 結果状態（Success/Failure等） |

### 出力先

- NUnitテストランナー
- テスト結果レポート

## 処理フロー

### 処理シーケンス

```
1. テスト属性評価
   └─ AvaloniaTestAttributeがIWrapSetUpTearDownを実装
2. TestCommand作成
   └─ Wrap()メソッドでAvaloniaTestMethodCommandにラップ
3. コマンドチェーン処理
   └─ ProcessCommand()でSetUp/TearDownを抽出
   └─ 元のコマンドを再帰的に処理
4. テスト実行
   └─ Execute()でDispatcher.UIThread上で実行
   └─ SetUp → テストメソッド → TearDown の順序
5. 非同期処理
   └─ Task/ValueTaskをawait
```

### フローチャート

```mermaid
flowchart TD
    A[NUnitテストランナー] --> B[AvaloniaTestAttribute.Wrap]
    B --> C[HeadlessUnitTestSession取得]
    C --> D[ProcessCommand]
    D --> E{DelegatingTestCommand?}
    E -->|Yes| F[BeforeTest/AfterTest抽出]
    E -->|No| G[AvaloniaTestMethodCommand作成]
    F --> H[InnerCommand再帰処理]
    H --> D
    G --> I[Execute実行]
    I --> J[session.DispatchCore]
    J --> K[ExecuteTestMethod]
    K --> L[beforeTest実行]
    L --> M[テストメソッド呼び出し]
    M --> N[afterTest実行]
    N --> O[TestResult返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-105-1 | Dispatcherスレッド実行 | テストメソッド、SetUp、TearDownはすべてDispatcher上で実行 | 常時 |
| BR-105-2 | コマンドチェーン | NUnitのコマンドチェーンを解析しAvaloniaコマンドに変換 | 常時 |
| BR-105-3 | 非同期サポート | Task、ValueTaskの戻り値を適切にawait | 非同期テスト時 |
| BR-105-4 | ジョブ実行 | テスト後にDispatcher.UIThread.RunJobs()で保留ジョブを処理 | 常時 |

### 計算ロジック

特になし。

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

データベース操作なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| SESSION_INIT_FAIL | Exception | HeadlessUnitTestSession初期化失敗 | テストアプリケーション設定確認 |
| ASSERTION_FAIL | AssertionException | アサーション失敗 | テストコード確認 |

### リトライ仕様

リトライなし（NUnitのリトライ機構を使用）。

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

トランザクションなし。

## パフォーマンス要件

- セッション再利用によるアプリケーション初期化オーバーヘッド削減
- コマンドチェーン処理は初回のみ実行

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

特になし。

## 備考

- NUnit SynchronizationContextの制限により独自の同期処理を実装
- AvaloniaTheoryでパラメータ化テストが可能

---

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

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

### 推奨読解順序

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

テスト属性の構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | AvaloniaTest.cs | `src/Headless/Avalonia.Headless.NUnit/AvaloniaTest.cs` | AvaloniaTestAttribute定義、IWrapSetUpTearDown実装 |

**読解のコツ**: TestAttributeを継承しIWrapSetUpTearDownを実装。Wrap()メソッドでカスタムコマンドにラップ。

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

コマンドラッピングの起点を特定。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | AvaloniaTest.cs | `src/Headless/Avalonia.Headless.NUnit/AvaloniaTest.cs` | Wrap()（18-24行目）でHeadlessUnitTestSession取得とコマンド処理 |

**主要処理フロー**:
- **20-21行目**: HeadlessUnitTestSession.GetOrStartForAssemblyでセッション取得
- **23行目**: ProcessCommandでコマンドチェーンを処理

#### Step 3: コマンド処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | AvaloniaTestMethodCommand.cs | `src/Headless/Avalonia.Headless.NUnit/AvaloniaTestMethodCommand.cs` | ProcessCommand（31-74行目）でコマンドチェーン解析 |

**主要処理フロー**:
- **36-51行目**: BeforeAndAfterTestCommandからSetUp/TearDownを抽出
- **53-58行目**: DelegatingTestCommandの内部コマンドを再帰処理
- **70-71行目**: TestMethodCommandに到達したらAvaloniaTestMethodCommandを作成

#### Step 4: テスト実行処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | AvaloniaTestMethodCommand.cs | `src/Headless/Avalonia.Headless.NUnit/AvaloniaTestMethodCommand.cs` | Execute()（76-78行目）とExecuteTestMethod（82-107行目） |

**主要処理フロー**:
- **78行目**: session.DispatchCoreでDispatcher上で実行
- **84-85行目**: beforeTest群を実行
- **90-91行目**: テストメソッドを呼び出しawait
- **100-101行目**: afterTest群を実行
- **103行目**: Dispatcher.UIThread.RunJobs()で保留ジョブ処理

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

```
NUnitテストランナー
    │
    └─ AvaloniaTestAttribute.Wrap()
           │
           ├─ HeadlessUnitTestSession.GetOrStartForAssembly
           │      └─ AppBuilder.SetupWithoutStarting
           │
           └─ ProcessCommand (再帰)
                  │
                  ├─ BeforeAndAfterTestCommandの処理
                  │      └─ BeforeTest/AfterTest抽出
                  │
                  ├─ DelegatingTestCommandの処理
                  │      └─ InnerCommand取得
                  │
                  └─ TestMethodCommandの処理
                         └─ AvaloniaTestMethodCommand作成

AvaloniaTestMethodCommand.Execute
    │
    └─ session.DispatchCore
           │
           └─ ExecuteTestMethod
                  │
                  ├─ beforeTest群実行
                  ├─ テストメソッド呼び出し (await)
                  ├─ afterTest群実行
                  └─ Dispatcher.UIThread.RunJobs()
```

### データフロー図

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

テストメソッド ────────▶ AvaloniaTestAttribute.Wrap ────▶ AvaloniaTestMethodCommand
([AvaloniaTest])                │
                               ▼
                         ProcessCommand
                               │
                               ▼
TestMethodCommand ────────▶ AvaloniaTestMethodCommand ────▶ TestResult
                               │
                               ▼
                         session.DispatchCore
                               │
                               ▼
                         ExecuteTestMethod
                               │
                               ├─▶ SetUp実行
                               ├─▶ テストメソッド実行
                               └─▶ TearDown実行
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| AvaloniaTest.cs | `src/Headless/Avalonia.Headless.NUnit/AvaloniaTest.cs` | ソース | Test属性定義 |
| AvaloniaTheory.cs | `src/Headless/Avalonia.Headless.NUnit/AvaloniaTheory.cs` | ソース | Theory属性定義 |
| AvaloniaTestMethodCommand.cs | `src/Headless/Avalonia.Headless.NUnit/AvaloniaTestMethodCommand.cs` | ソース | テストコマンド実装 |
| NUnitReflectionHelper.cs | `src/Headless/Avalonia.Headless.NUnit/NUnitReflectionHelper.cs` | ソース | NUnit内部へのリフレクションアクセス |
