# IOS Test Design

> XCTest/XCUITestを用いたiOSアプリのテスト設計支援スキル。テスト戦略立案、モック/スタブ設計、テストデータ管理、カバレッジ分析を包括的にサポート。Use when: iOSテスト設計、XCTest実装、UITest作成、テストカバレッジ向上、テスト戦略立案、テストダブル設計。

- Skill: `caphtech/ios-test-design` (Agent Skill, multi-file: 5 files)
- Install (CLI): `npx skillmds@latest add caphtech/ios-test-design`
- Raw SKILL.md: https://api.skillmd.com/api/skills/caphtech/ios-test-design/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: CAPHTECH (https://skillmd.com/u/caphtech)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/caphtech/ios-test-design

---


# iOS Test Design（iOSテスト設計支援）

## 概要

XCTestおよびXCUITestを活用したiOSアプリケーションのテスト設計を支援するスキル。
デトロイト学派寄りのアプローチを採用し、実際のコンポーネント連携をテストすることで、信頼性の高いテストスイートを構築する。

### 対象範囲

- **Unit Test**: XCTestによる単体テスト設計
- **Integration Test**: コンポーネント間連携テスト
- **UI Test**: XCUITestによるUIテスト設計
- **テストダブル**: モック/スタブ/フェイク/スパイの設計
- **テストデータ**: フィクスチャ、ファクトリ、シード管理

## 実行条件

以下の状況でこのスキルを起動する：

- iOSアプリのテスト設計・実装を行う時
- 既存テストのリファクタリングを検討する時
- テストカバレッジを向上させたい時
- テストダブル（モック/スタブ）の設計を相談したい時
- テスト戦略を立案したい時
- テストの保守性・可読性を改善したい時

## プロセス

### Phase 1: テスト対象の分析

#### 1.1 対象コードの理解

1. テスト対象のクラス/構造体/関数を特定
2. 依存関係を洗い出す
3. 公開インターフェースを確認
4. 副作用（ネットワーク、永続化、通知等）を特定

#### 1.2 テスト可能性の評価

| 評価項目 | 確認内容 |
|---------|---------|
| 依存性注入 | コンストラクタ/プロパティ経由で差し替え可能か |
| 副作用の分離 | I/O操作がプロトコル経由で抽象化されているか |
| 状態の観測 | 内部状態の変化を外部から検証可能か |
| 決定論性 | 同一入力に対して同一出力が保証されるか |

### Phase 2: テスト戦略の策定

#### テストレベル別の方針

| レベル | 対象 | テストダブル | 実行頻度 |
|-------|------|------------|---------|
| Unit | ビジネスロジック、ViewModel、Utility | スタブ/モック | 常時 |
| Integration | UseCase + Repository、View + ViewModel | スタブ（外部境界のみ） | PR/CI |
| UI | 主要ユーザーフロー | なし（実環境に近づける） | デイリー/リリース |

### Phase 3: XCTestによるUnitテスト設計

詳細は references/xctest-patterns.md を参照。

#### 3.1 テストケースの構造

```swift
final class SampleTests: XCTestCase {
    
    // MARK: - Properties
    private var sut: SystemUnderTest!
    private var mockDependency: MockDependency!
    
    // MARK: - Setup/Teardown
    override func setUp() {
        super.setUp()
        mockDependency = MockDependency()
        sut = SystemUnderTest(dependency: mockDependency)
    }
    
    override func tearDown() {
        sut = nil
        mockDependency = nil
        super.tearDown()
    }
    
    // MARK: - Tests
    func test_methodName_condition_expectedBehavior() {
        // Given（前提条件）
        let input = ...
        
        // When（実行）
        let result = sut.method(input)
        
        // Then（検証）
        XCTAssertEqual(result, expected)
    }
}
```

#### 3.2 命名規則

```
test_<対象メソッド>_<条件>_<期待される振る舞い>

例:
test_login_withValidCredentials_returnsSuccess
test_fetchUser_whenNetworkError_throwsError
test_calculate_withNegativeInput_returnsZero
```

### Phase 4: テストダブルの設計

詳細は references/test-doubles.md を参照。

#### プロトコルベースのテストダブル

```swift
// 抽象化されたプロトコル
protocol UserRepositoryProtocol {
    func fetch(id: String) async throws -> User
}

// 本番実装
final class UserRepository: UserRepositoryProtocol { ... }

// テストダブル
final class MockUserRepository: UserRepositoryProtocol {
    var fetchResult: Result<User, Error> = .success(User.stub)
    var fetchCallCount = 0
    var lastFetchedId: String?
    
    func fetch(id: String) async throws -> User {
        fetchCallCount += 1
        lastFetchedId = id
        return try fetchResult.get()
    }
}
```

### Phase 5: XCUITestによるUIテスト設計

詳細は references/xcuitest-patterns.md を参照。

#### 5.1 Page Objectパターン

```swift
// Page Object
final class LoginPage {
    private let app: XCUIApplication
    
    var emailField: XCUIElement { app.textFields["email"] }
    var passwordField: XCUIElement { app.secureTextFields["password"] }
    var loginButton: XCUIElement { app.buttons["login"] }
    
    init(app: XCUIApplication) {
        self.app = app
    }
    
    func login(email: String, password: String) -> HomePage {
        emailField.tap()
        emailField.typeText(email)
        passwordField.tap()
        passwordField.typeText(password)
        loginButton.tap()
        return HomePage(app: app)
    }
}
```

#### 5.2 Accessibility Identifierの設計

| 要素 | 命名規則 | 例 |
|-----|---------|---|
| 画面 | `<screen>_screen` | `login_screen` |
| ボタン | `<action>_button` | `submit_button` |
| テキストフィールド | `<field>_field` | `email_field` |
| ラベル | `<content>_label` | `error_label` |
| セル | `<item>_cell_<index>` | `user_cell_0` |

### Phase 6: テストデータ管理

詳細は references/test-data.md を参照。

#### 6.1 Factoryパターン

```swift
enum UserFactory {
    static func make(
        id: String = UUID().uuidString,
        name: String = "Test User",
        email: String = "test@example.com",
        isActive: Bool = true
    ) -> User {
        User(id: id, name: name, email: email, isActive: isActive)
    }
    
    static var activeUser: User { make(isActive: true) }
    static var inactiveUser: User { make(isActive: false) }
}
```

#### 6.2 フィクスチャファイル

```
Tests/
├── Fixtures/
│   ├── JSON/
│   │   ├── user_response.json
│   │   └── error_response.json
│   └── Stubs/
│       └── UserStub.swift
```

### Phase 7: テストカバレッジ分析

#### Xcodeでのカバレッジ確認

1. スキーム設定 → Test → Options → Code Coverage有効化
2. `Cmd + U` でテスト実行
3. Report Navigator → Coverage でレポート確認

#### カバレッジ改善の優先順位

1. **ビジネスロジック**: Domain層、UseCase層
2. **状態管理**: ViewModel、Reducer
3. **データ変換**: Mapper、Parser、Formatter
4. **エラーハンドリング**: 例外処理、リトライロジック

## 出力形式

### テスト設計ドキュメント

```markdown
# テスト設計書: <機能名>

## 1. テスト対象
- クラス/構造体: `ClassName`
- 責務: 〇〇を行う

## 2. テスト戦略
- テストレベル: Unit / Integration / UI
- テストダブル: 使用する依存のリスト

## 3. テストケース一覧
| ID | カテゴリ | テスト内容 | 期待結果 |
|----|---------|----------|---------|
| TC-001 | 正常系 | ... | ... |
| TC-002 | 異常系 | ... | ... |

## 4. テストダブル設計
- MockXxx: 〇〇の呼び出しを検証
- StubYyy: 〇〇の値を返す

## 5. テストデータ
- Factory: XxxFactory
- Fixture: xxx_response.json
```

### テストコード

```swift
import XCTest
@testable import TargetModule

final class FeatureTests: XCTestCase {
    // 上記パターンに従ったテストコード
}
```

## ガードレール

### 必須遵守事項

1. **テストの独立性**: 各テストは他のテストに依存しない
2. **テストの決定論性**: 同じ条件で常に同じ結果
3. **テストの高速性**: Unitテストは1秒以内に完了
4. **明確な命名**: テスト名から内容が分かる

### 禁止事項

1. **本番コードのテスト用変更**: テストのために本番コードにテスト用分岐を入れない
2. **ネットワーク依存**: Unitテストで実ネットワークアクセスしない
3. **時間依存**: `Date()` 直接使用ではなく注入する
4. **グローバル状態**: シングルトンの直接参照を避ける

### 警告事項

1. **過度なモック**: 全てをモックすると実装詳細への依存が増す
2. **テストの重複**: 同じ振る舞いを複数箇所でテストしない
3. **実装の検証**: 「どう動くか」ではなく「何をするか」をテスト

## 参照

- references/xctest-patterns.md: XCTestパターン集
- references/xcuitest-patterns.md: XCUITestパターン集
- references/test-doubles.md: テストダブル設計ガイド
- references/test-data.md: テストデータ管理ガイド

