コンテンツにスキップ

2.2. 結合テスト規定

このドキュメントは、結合テスト(インテグレーションテスト)の実装に関する具体的な規約を定めます。結合テストは、個々のユニットが連携した際に、システムとして正しく機能することを保証します。

1. 結合テストの定義と目的

  • 定義:
    • 結合テストとは、複数のコンポーネント(ユニット)を組み合わせて、それらが連携する部分を検証するテストです。
    • 単体テストではモックやスタブで置き換えていた、実際の外部依存(データベース、ファイルシステム、外部APIなど)と接続してテストを行います。
  • 目的:
    • コンポーネント間のインターフェースの不整合(データ形式の違い、呼び出し規約の誤りなど)を検出します。
    • 外部サービスとの接続が正しく行えることを検証します。(例: データベースのスキーマとO/Rマッパーのエンティティ定義が一致しているか)
    • 単体テストでは見つけられない、複数のコンポーネントが絡み合った複雑なシナリオでのバグを検出します。

2. 結合テストのスコープ(対象範囲)

結合テストで検証すべき、代表的な連携ポイントは以下の通りです。

  • データベース連携:
    • アプリケーションのロジックが、実際のデータベースに対して、正しくデータの読み書き(CRUD)を行えるか。
    • トランザクションが期待通りに機能するか(コミット、ロールバック)。
  • ファイルシステム連携:
    • ファイルの読み書き、フォルダの作成・削除などが正しく行えるか。
  • 外部API連携:
    • サードパーティのAPIや、マイクロサービス間のAPI呼び出しが、実際のエンドポイントに対して正しく行えるか。
  • メッセージキュー連携:
    • メッセージの送受信が、実際のブローカー(RabbitMQ, Kafkaなど)を通じて正しく行えるか。
  • APIエンドポイントのテスト:
    • APIのコントローラー層から、ビジネスロジック層、データアクセス層までを含めた一連のフローをテストする。HTTPリクエストを実際に送信し、レスポンスを検証します。

3. テスト環境の管理

結合テストは実際の外部サービスと連携するため、テスト環境の管理が極めて重要です。

  • 原則: ローカルで完結させる:
    • 可能な限り、Docker Compose などを活用し、必要なデータベースや外部サービスをローカルコンテナとして起動し、テストを実行できる環境を構築することを強く推奨します。
    • これにより、他の開発者やCI環境との競合を避け、誰でも安定してテストを実行できます。
  • テスト用データベース:
    • テストごとに、データベースの状態をクリーンな状態にリセットする必要があります。
    • 戦略1 (推奨): 各テストの実行前にトランザクションを開始し、テスト終了後にロールバックする。
    • 戦略2: 各テストの実行前に、スキーマを再作成し、テストデータを投入する。
  • 設定とシークレット:
    • テスト環境用の接続文字列やAPIキーは、ソースコードにハードコーディングせず、設定ファイルや環境変数から読み込むようにします。CI環境では、GitHub Secretsなどを使って安全に管理します。

4. 結合テストの実装パターン

4.1. APIエンドポイントテスト

  • 目的: APIの振る舞いを、外部のクライアント視点で検証します。
  • 推奨ツール:
    • C# (ASP.NET Core): Microsoft.AspNetCore.Mvc.TestingWebApplicationFactoryを利用し、インメモリでテストサーバーを起動してテストします。
    • Python (FastAPI/Flask): TestClientを利用します。
    • TypeScript (Node.js/Express): Supertestなどのライブラリを利用します。

C# でのテスト例 (WebApplicationFactory):

public class UserControllerTests : IClassFixture<WebApplicationFactory<Program>>
{
private readonly HttpClient _client;

    public UserControllerTests(WebApplicationFactory<Program> factory)
    {
        _client = factory.CreateClient();
    }

    [Fact]
    public async Task GetUser_WithValidId_ReturnsOk()
    {
        // Act
        var response = await _client.GetAsync("/api/users/1");

        // Assert
        response.EnsureSuccessStatusCode(); // Status Code 200-299
        var user = await response.Content.ReadFromJsonAsync<UserDto>();
        Assert.NotNull(user);
        Assert.Equal(1, user.Id);
    }

}

5. 注意事項

  • 実行速度: 結合テストは単体テストに比べて実行が遅いため、数は単体テストよりも少なくなるべきです(テストピラミッド)。
  • 不安定さ (Flakiness): ネットワークや外部サービスの状況によって、テストが時々失敗する(Flaky Test)可能性があります。失敗の原因がテスト対象のコードにあるのか、環境にあるのかを切り分けられるように設計し、リトライ処理の導入などを検討します。
  • CIでの実行: 実行時間が長いため、CIパイプラインでは、単体テストとは別のステージとして実行することを推奨します。Pull Request時には必須としつつ、プッシュごとの実行はスキップするなどの戦略も考えられます。