슬라이스 테스트
애플리케이션의 특정 계층(슬라이스)만 선택적으로 로딩하여 검증하는 Spring Boot 특화 테스트 기법입니다.
왜 필요한가?
@SpringBootTest는 모든 Bean을 로딩하므로 느리고 무겁습니다. 슬라이스 테스트는 테스트에 필요한 계층의 Bean만 로딩하여 통합 테스트의 신뢰성과 단위 테스트의 속도 사이 균형을 잡습니다.
@SpringBootTest → [Controller + Service + Repository + DB + ...] 전부 로딩
@WebMvcTest → [Controller + MVC 관련]만 로딩
@DataJpaTest → [Repository + JPA 관련]만 로딩
주요 슬라이스 어노테이션
| 어노테이션 | 대상 계층 | 로딩되는 Bean | 대표 용도 |
|---|---|---|---|
@WebMvcTest | Controller | @Controller, @ControllerAdvice, Filter 등 | 요청/응답, 검증, 예외 처리 |
@DataJpaTest | Repository | @Repository, EntityManager, 내장 DB | 쿼리, 매핑, 연관관계 검증 |
@DataMongoTest | MongoDB | Mongo Repository, Template | MongoDB 쿼리 검증 |
@RestClientTest | 외부 API | RestTemplate, WebClient | 외부 API 호출/응답 검증 |
@JsonTest | JSON 직렬화 | ObjectMapper, @JsonComponent | JSON 변환 로직 검증 |
@WebFluxTest | WebFlux Controller | @Controller (리액티브) | 리액티브 엔드포인트 검증 |
Java 예시
1. @WebMvcTest — Controller 계층 테스트
@WebMvcTest(OrderController.class)
class OrderControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean // Service 계층은 Mock으로 대체
private OrderService orderService;
@Test
@DisplayName("주문 조회 시 200 OK와 주문 정보를 반환한다")
void getOrder() throws Exception {
// Given
OrderResponse response = new OrderResponse(1L, "키보드", 10_000);
given(orderService.findById(1L)).willReturn(response);
// When & Then
mockMvc.perform(get("/api/orders/{id}", 1L))
.andExpect(status().isOk())
.andExpect(jsonPath("$.productName").value("키보드"))
.andExpect(jsonPath("$.price").value(10_000));
}
@Test
@DisplayName("존재하지 않는 주문 조회 시 404를 반환한다")
void getOrder_notFound() throws Exception {
given(orderService.findById(99L))
.willThrow(new OrderNotFoundException(99L));
mockMvc.perform(get("/api/orders/{id}", 99L))
.andExpect(status().isNotFound());
}
}
2. @DataJpaTest — Repository 계층 테스트
@DataJpaTest
class ProductRepositoryTest {
@Autowired
private ProductRepository productRepository;
@Autowired
private TestEntityManager em;
@Test
@DisplayName("가격 범위로 상품을 조회한다")
void findByPriceRange() {
// Given
em.persist(new Product("마우스", 5_000, 50));
em.persist(new Product("키보드", 10_000, 30));
em.persist(new Product("모니터", 300_000, 10));
em.flush();
// When
List<Product> result = productRepository
.findByPriceBetween(1_000, 50_000);
// Then
assertThat(result).hasSize(2)
.extracting("name")
.containsExactlyInAnyOrder("마우스", "키보드");
}
}
테스트 방식 비교
| 항목 | 단위 테스트 | 슬라이스 테스트 | @SpringBootTest |
|---|---|---|---|
| Bean 로딩 | 없음 (순수 Java) | 해당 계층만 | 전체 |
| 속도 | 매우 빠름 | 빠름 | 느림 |
| 외부 의존성 | Mock | 내장 DB 또는 Mock | 실제 또는 테스트 환경 |
| 검증 범위 | 메서드/클래스 | 특정 계층 | 전체 흐름 |
| Spring 컨텍스트 | 미사용 | 부분 로딩 | 전체 로딩 |
슬라이스 테스트 시 주의사항
@MockBean남용 주의: Mock이 많아지면 실제 동작과 괴리가 생길 수 있음- 내장 DB 차이:
@DataJpaTest는 기본적으로 H2 내장 DB를 사용하므로, 운영 DB(MySQL 등)와 SQL 문법 차이가 발생할 수 있음 → 필요 시@AutoConfigureTestDatabase(replace = NONE)+ Testcontainers 활용 - 컨텍스트 캐싱: 동일한 슬라이스 설정을 사용하는 테스트 클래스들은 Spring 컨텍스트를 재사용하므로,
@MockBean구성이 다르면 별도 컨텍스트가 생성되어 오히려 느려질 수 있음
실무 팁: Controller는
@WebMvcTest, Repository는@DataJpaTest로 각 계층을 빠르게 검증하고, 계층 간 연동이 중요한 핵심 시나리오만@SpringBootTest로 테스트하는 전략이 효과적입니다.