🚀 Spring Framework 講座【第40回】複数層をまとめて検証!〜結合テスト(Integration Test)の基本〜

docs

前回、単体テストによって、個々のクラス(ServiceやController)のロジックが正しいことを、モックを使って検証する方法を学びました。

しかし、単体テストだけでは以下の重要な点は検証できません。

  1. DIコンテナの動作: @Autowired@Component が正しく設定され、**SpringのDI(依存性注入)**が意図した通りに行われているか。
  2. 層間の連携: ControllerからService、ServiceからRepositoryへのデータ受け渡しが正しく機能しているか。
  3. 永続化: @Transactional や JPA のマッピングが正しく、実際にデータベースにデータが書き込まれているか

今回は、これらの複数の要素を結合して検証する**結合テスト(Integration Test)**の書き方を学びます。


1. 結合テストとは?

結合テストは、アプリケーションを構成する複数のコンポーネントや層を組み合わせて、エンドツーエンドに近い動作を検証するテストです。

  • 特徴: Spring BootのDIコンテナを実際に起動し、本物に近い環境でテストを実行します。
  • 目的: 開発者が記述したビジネスロジックだけでなく、Spring Frameworkが提供するフレームワーク機能(DI、トランザクション、MVCマッピングなど)の動作保証を主な目的とします。

2. Spring Boot Testの基本的な構成

結合テストを行うには、Spring Bootのテスト機能を使います。

2-1. @SpringBootTest アノテーション

テストクラスに @SpringBootTest アノテーションを付与すると、Spring Bootアプリケーションの起動に必要なすべての設定(@SpringBootApplication など)を読み込み、DIコンテナを起動します。

Java

import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles; // テスト用プロファイルの使用

@SpringBootTest 
@ActiveProfiles("test") // テスト用の設定ファイル(application-test.ymlなど)を使用
class ItemServiceIntegrationTest {
    
    // 起動したコンテナから本物のServiceを注入する
    @Autowired 
    private ItemService itemService; 

    // ... Repositoryも注入して、テスト後のデータを確認することも可能
    @Autowired
    private ItemRepository itemRepository;

    // ... テストメソッド
}

このとき、@Autowired で注入される itemService は、本物の Service クラスのインスタンスであり、その中に注入されている itemRepository も本物の Repository のインスタンスです。

2-2. テスト環境の分離(テストプロファイル)

結合テストではDBアクセスが発生するため、開発用や本番用のDBを汚染しないよう、テスト専用のDBを使うのが鉄則です。

  • テストプロファイル: application-test.yml などの設定ファイルを用意し、テスト専用のH2データベース(インメモリDB)などの設定を記述します。
  • @ActiveProfiles("test") を付けることで、このテスト実行時のみテストプロファイルが適用されます。

3. トランザクションとロールバック

結合テストでデータを作成・更新した後、そのテストが終わるたびにDBからデータを削除する作業は手間がかかります。

Spring Bootの結合テストでは、@Transactional アノテーションをテストメソッドに付与することで、この手間を解消できます。

Java

import org.springframework.transaction.annotation.Transactional;

@SpringBootTest
class ItemServiceIntegrationTest {
    
    // ... @Autowired で Service を注入
    
    @Test
    @Transactional // テストメソッドの実行後に、自動でDB変更をロールバック(取り消し)する
    void testItemCreationAndFind() {
        
        // 1. データの作成(DBに書き込まれる)
        Long newId = itemService.createItem("テスト商品", 100); 
        
        // 2. データの検証(DBから読み取る)
        Item createdItem = itemRepository.findById(newId).orElseThrow();
        assertEquals("テスト商品", createdItem.getName());
        
        // 3. メソッド終了後、@Transactional により、作成したデータはDBから自動で削除される(ロールバック)
    }
}

テストクラスやメソッドに @Transactional を付けると、テスト終了時に全てのDB操作が自動でロールバックされ、次のテストに影響を与えないクリーンな状態を保てます。

4. Controller層のテスト(Web層の検証)

Webアプリケーションの結合テストで最も頻繁に行われるのが、Controller層の検証です。外部からHTTPリクエストを送信し、正しいレスポンス(HTTPステータスコード、JSONボディなど)が返ってくるかを検証します。

これには、Spring Bootが提供する MockMvc クラスを使用します。

Java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@SpringBootTest
@AutoConfigureMockMvc // MockMvcを自動設定し、DI可能にする
class ItemControllerIntegrationTest {

    @Autowired
    private MockMvc mockMvc; // サーバーを起動せずにHTTPリクエストをシミュレーションする

    @Test
    void testGetItem_Success() throws Exception {
        
        // 1. HTTP GETリクエストをシミュレーション
        mockMvc.perform(get("/api/items/1")) 
               // 2. 検証 (HTTPステータスコードが200 OKであること)
               .andExpect(status().isOk()) 
               // 3. 検証 (レスポンスボディのJSONに含まれる name フィールドが期待値であること)
               .andExpect(jsonPath("$.name").value("既存の商品名")); 
    }
}

MockMvc は、実際にTomcatなどのWebサーバーを起動することなく、Spring MVCの処理パイプラインだけを通してリクエストを処理するため、非常に高速なWeb層のテストが可能です。

✅ 本日のまとめ

  • 結合テストは、@SpringBootTest でDIコンテナを起動し、複数層(Controller, Service, Repository)の連携とフレームワークの動作を検証する。
  • テスト専用のDBを使用するため、@ActiveProfiles("test") でテストプロファイルを適用する。
  • テストメソッドに @Transactional を付与することで、テスト実行後にDBの変更が自動でロールバックされ、テスト環境がクリーンに保たれる。
  • Controller層のテストには、WebサーバーなしでHTTPリクエストをシミュレーションできる MockMvc を使用する。

🔔 次回予告

単体テストと結合テストの知識が揃ったことで、堅牢なアプリケーション開発の基盤が整いました。

次回からは、アプリケーションのデプロイ(配置)と運用に関する実践的なテーマに進みます。次回は、構築したSpring Bootアプリケーションをコンテナ化するための Docker の基本と、Dockerfileの書き方を学びます。

次回:【第41回】アプリケーションのコンテナ化!〜Dockerの基本とDockerfile〜 にご期待ください!

コメント

タイトルとURLをコピーしました