전체 애플리케이션이 아니라 필요한 계층만 띄우는 테스트.
종류
@WebMvcTest(OrderController.class) // 컨트롤러 · 필터 · 컨버터만. 서비스는 @MockitoBean 으로
@DataJpaTest // JPA 관련 빈 + 내장 DB. 기본으로 롤백된다
@JsonTest · @RestClientTest · @DataRedisTest ...
@WebMvcTest(OrderController.class)
class OrderControllerTest {
@Autowired MockMvc mvc;
@MockitoBean OrderService service; // Boot 3.4+ (이전엔 @MockBean)
@Test void 주문_조회() throws Exception {
given(service.find(1L)).willReturn(new OrderDto(1L, "PAID"));
mvc.perform(get("/orders/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.status").value("PAID"));
}
}
어떻게 조각만 뜨나
슬라이스 애노테이션은 @TypeExcludeFilter 로
- '이 슬라이스에 필요한 빈' 만 스캔 대상으로 남긴다
- @Service · @Repository 는 등록되지 않는다
- 그래서 목으로 채워야 한다
왜 스위트가 점점 느려지나 — 컨텍스트 캐싱
Spring 은 테스트마다 컨텍스트를 새로 만들지 않는다
- '설정이 같으면' 캐시해서 재사용한다
캐시 키가 달라지는 조건
- 애노테이션 조합이 다르다
- @MockitoBean 대상이 다르다 ← 가장 흔한 원인
- @ActiveProfiles · @TestPropertySource 가 다르다
키가 다를 때마다 컨텍스트가 하나씩 더 생긴다
- 20개면 기동 20번. 스위트가 몇 분씩 걸리게 된다
# 컨텍스트가 몇 개나 만들어졌는지 로그로 확인한다
logging.level.org.springframework.test.context.cache=DEBUG
목 대상을 공통 설정으로 모으고 프로필 조합을 줄이는 것이 스위트 속도 개선의 핵심이다.
진짜에 가깝게 — Testcontainers
@SpringBootTest
@Testcontainers
class OrderIntegrationTest {
@Container
@ServiceConnection // Boot 3.1+ : 접속 정보를 자동 주입
static PostgreSQLContainer<?> db = new PostgreSQLContainer<>("postgres:17");
}
내장 H2 로 테스트하면
- 방언이 달라 실제 SQL 이 다르게 나간다
- 락·격리수준·인덱스 동작이 운영과 다르다
- "테스트는 통과했는데 운영에서 터진다"
Testcontainers 는 실제 DB 를 도커로 띄운다
- 느리지만 신뢰할 수 있다. 재사용 설정으로 속도를 보완한다
면접 함정
- ❌ "@SpringBootTest로 다 하면 편하다" → 전체 컨텍스트가 매번 떠서 스위트가 급격히 느려진다.
- ❌ "@DataJpaTest는 실제 DB를 쓴다" → 기본은 내장 DB로 대체된다(
@AutoConfigureTestDatabase로 끌 수 있다).