Spring Bootでテストを書くたびに「これは @SpringBootTest でいいのか、@WebMvcTest を使うべきか」と検索し直していませんか。とりあえず全部 @SpringBootTest で書いた結果、テストの実行に数分かかるようになったプロジェクトもよく見かけますよね。

この記事では、テスト対象のレイヤーから使うべきアノテーションを即決できる早見表と判断フローをまとめます。各アノテーションの最小サンプルも載せますが、詳しい実装はそれぞれの個別記事へ誘導するハブ記事として使ってください。

まず結論の早見表

テスト対象から引ける形で整理すると、こうなります。

アノテーション起動する範囲速度主な用途併用するモック手段
なし(素のJUnit)起動しない最速Serviceの単体テストMockito
@WebMvcTestMVC関連Beanのみ速いControllerの入出力検証@MockitoBean + MockMvc
@DataJpaTestJPA関連Beanのみ速いRepositoryのクエリ検証原則モックなし
@JsonTestJackson関連のみ最速級JSONシリアライズ検証不要
@RestClientTestクライアントBeanのみ速い外部API呼び出し検証MockRestServiceServer
@SpringBootTest全Bean遅い複数レイヤーの結合検証Testcontainers / WireMock

MongoDBなら @DataMongoTest、JDBCなら @JdbcTest というように、他のスライステストも同じ発想で用意されています。

判断フローはシンプルです。

  1. Serviceのロジックを検証したいなら、アノテーション不要。素のJUnit + Mockitoで書く
  2. Controllerなら @WebMvcTest、Repositoryなら @DataJpaTest などレイヤー対応のスライステストを選ぶ
  3. 複数レイヤーを貫通する検証だけ @SpringBootTest を使う

基本方針は「まずスライステスト、@SpringBootTest は結合テストのみ」です。

なぜ「全部@SpringBootTest」だと遅いのか

@SpringBootTest はアプリの全Beanを含むApplicationContextを起動します。DB接続やセキュリティ設定まで全部です。一方スライステストは対象レイヤーのBeanだけを起動するので、1回あたりの起動コストが大きく違います。

「でもコンテキストはキャッシュされるのでは?」と思いますよね。確かにSpringのテストフレームワークは同一設定のコンテキストを再利用します。ただしキャッシュが効くのは設定が完全に一致する場合だけで、@MockitoBean の対象が違う、@TestPropertySource でプロパティを変えた、といったテストクラスごとの差分があるとキャッシュミスになり、その都度フル起動が走ります。

つまり @SpringBootTest をあちこちで使うほど「フル起動 × キャッシュミス回数」でビルドが延びていくわけです。単一レイヤーの検証はスライステストに寄せて、この掛け算自体を小さくしましょう。

Controller層は@WebMvcTest + MockMvc

@WebMvcTest が起動するのはControllerやFilter、Jackson設定といったMVC関連のBeanだけです。ServiceやRepositoryは含まれないので、依存するServiceは @MockitoBean で差し替えます。

@WebMvcTest(UserController.class)
class UserControllerTest {

    @Autowired
    MockMvc mockMvc;

    @MockitoBean
    UserService userService;

    @Test
    void getUser_returnsOk() throws Exception {
        when(userService.findById(1L))
                .thenReturn(new UserResponse(1L, "alice"));

        mockMvc.perform(get("/api/users/1"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.name").value("alice"));
    }
}

リクエストの組み立てやバリデーション検証のパターンは MockMvcによるControllerテストの記事 で詳しく扱っています。

Service層はアノテーション不要

見落とされがちですが、Serviceの単体テストにSpringのアノテーションは要りません。コンテキストを一切起動せず、@ExtendWith(MockitoExtension.class)@Mock / @InjectMocks だけで完結します。

@ExtendWith(MockitoExtension.class)
class UserServiceTest {

    @Mock
    UserRepository userRepository;

    @InjectMocks
    UserService userService;

    @Test
    void findById_returnsUser() {
        when(userRepository.findById(1L))
                .thenReturn(Optional.of(new User(1L, "alice")));

        UserResponse result = userService.findById(1L);

        assertThat(result.name()).isEqualTo("alice");
        verify(userRepository).findById(1L);
    }
}

コンテキスト起動がないので実行は一瞬です。ビジネスロジックの検証はここに寄せるのが理想ですね。when / verify の基本文法は JUnitとMockitoによるテスト入門記事 を参照してください。

Repository層は@DataJpaTest

@DataJpaTest はRepositoryや EntityManager などJPA関連のBeanだけを起動し、デフォルトでDBをインメモリDBに自動置換します。各テスト後に自動ロールバックされるので、データの後始末も不要です。

@DataJpaTest
class UserRepositoryTest {

    @Autowired
    TestEntityManager em;

    @Autowired
    UserRepository userRepository;

    @Test
    void findByEmail_returnsUser() {
        em.persist(new User("alice", "[email protected]"));
        em.flush();

        Optional<User> found = userRepository.findByEmail("[email protected]");

        assertThat(found).isPresent();
    }
}

PostgreSQL固有のSQLなど本番同等のDBで検証したい場合は、Testcontainersと組み合わせる発展形があります。使い分けの詳細は @DataJpaTestのスライステスト記事Testcontainersの記事 にまとめています。

JSONの検証は@JsonTest

日付フォーマットやプロパティ命名規則など、Jackson設定の検証だけならControllerを起動する必要はありません。@JsonTest はJackson関連のBeanだけを起動する最軽量級のスライステストです。

@JsonTest
class UserResponseJsonTest {

    @Autowired
    JacksonTester<UserResponse> json;

    @Test
    void serialize_formatsDate() throws Exception {
        var response = new UserResponse("alice", LocalDate.of(2026, 9, 2));

        assertThat(json.write(response))
                .extractingJsonPathStringValue("$.created_at")
                .isEqualTo("2026-09-02");
    }
}

ObjectMapperのカスタマイズが増えてきたプロジェクトでは重宝しますよ。

外部APIクライアントは@RestClientTest

RestClientRestTemplate で外部APIを呼ぶクライアントには @RestClientTest があります。対象のクライアントBeanと MockRestServiceServer だけを起動し、実際のHTTP通信なしで応答処理を検証できます。

@RestClientTest(WeatherClient.class)
class WeatherClientTest {

    @Autowired
    WeatherClient weatherClient;

    @Autowired
    MockRestServiceServer server;

    @Test
    void getWeather_parsesResponse() {
        server.expect(requestTo("/weather/tokyo"))
                .andRespond(withSuccess("{\"condition\":\"sunny\"}",
                        MediaType.APPLICATION_JSON));

        assertThat(weatherClient.getWeather("tokyo").condition())
                .isEqualTo("sunny");
    }
}

WebClientを使っている場合や、タイムアウト・リトライまで含めた検証をしたい場合は、実HTTPサーバーを立てるWireMockが向いています。WireMockによる外部APIテストの記事 で比較しています。

@SpringBootTestを使うべき場面

ここまで読むと @SpringBootTest が悪者に見えるかもしれませんが、避けるものではなく適所で使うものです。Controller→Service→Repositoryを貫通するシナリオ検証、セキュリティ設定やBean定義・プロパティ解決の検証は @SpringBootTest の出番です。

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class UserApiIntegrationTest {

    @Autowired
    TestRestTemplate restTemplate;

    @Test
    void getUser_endToEnd() {
        var response = restTemplate.getForEntity("/api/users/1", UserResponse.class);

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
    }
}

webEnvironment はデフォルトのMOCK(モックサーブレット環境 + MockMvc)と、実際にポートを開くRANDOM_PORT(+ TestRestTemplate)を使い分けます。実DBやKafkaを含めた結合テストの組み方は @SpringBootTestとTestcontainersによる結合テスト記事 で解説しています。結合テストの本数は絞って、日常の検証はスライステストに寄せましょう。

@MockBeanは非推奨、@MockitoBeanへ

1点注意です。長らく使われてきた @MockBean / @SpyBean は、Spring Framework 6.2(Spring Boot 3.4)で非推奨になり、Spring Framework本体の @MockitoBean / @MockitoSpyBean に置き換わりました。この記事のサンプルもすべて @MockitoBean で統一しています。

importを org.springframework.boot.test.mock.mockito.MockBean から org.springframework.test.context.bean.override.mockito.MockitoBean に変え、アノテーション名を置換すればほぼ完了しますが、細かい非互換もあります。詳しくは @MockBeanから@MockitoBeanへの移行記事 を参照してください。

ツールとの組み合わせ対応表

最後に、モック・テストツールがどのアノテーションと組み合わさるかを整理しておきます。「アノテーションがコンテキストの範囲を決め、ツールが境界の外を偽装する」と考えると覚えやすいですよ。

テスト対象アノテーション組み合わせるツール
ServiceなしMockito(when / verify
Controller@WebMvcTestMockMvc + @MockitoBean
Repository@DataJpaTest必要ならTestcontainers
JSON変換@JsonTestJacksonTester
外部APIクライアント@RestClientTestMockRestServiceServer
結合テスト@SpringBootTestTestcontainers / WireMock

まとめ

迷ったらこの順で考えましょう。

  1. テスト対象のレイヤーを特定する
  2. 対応するスライステスト、Serviceなら素のJUnit + Mockitoを選ぶ
  3. レイヤーをまたぐ検証だけ @SpringBootTest にする

「まずスライステスト、@SpringBootTest は結合テストのみ」。この方針だけでテストの実行時間は大きく変わります。深掘りしたいレイヤーが決まったら、各セクションで紹介した個別記事へ進んでみてください。