✅ Slice Test는 Spring에서 특정 레이어(Controller, Repository 등)만 테스트하는 방식
✅ 애플리케이션 전체를 로드하는 것이 아니라, 필요한 빈(Bean)만 로드하여 테스트 속도를 향상
✅ 각 레이어별로 독립적인 단위 테스트를 수행할 수 있도록 도움
📌 필요성
vs Unit Test
Unit Test는 특정 클래스만 테스트하기 때문에 Spring Context를 사용하지 않는다. 따라서 다른 Spring Bean과의 연동 테스트가 어렵다.
반면, Slice Test는 각 레이어의 필요한 빈을 로드하기 때문에 특정 레이어의 연동 테스트가 가능하다.
vs SpringBootTest
SpringBootTest는 Spring Context를 사용하고, 다른 Spring Bean과의 연동 테스트가 가능하다. 하지만 애플리케이션 전체를 로드하기 때문에 시간이 오래걸리고 무겁다.
반면, Slice Test는 특정 레이어의 빈들만 로드하기 때문에 비교적 가볍다.
📌 Web Layer Slice Test
✅ Web Layer Bean들만 로드하여 테스트하는 방법
✅ Service 및 Repository는 로드되지 않으며, Service는 Mock으로 주입해야 함
@WebMvcTest
@WebMvcTest 어노테이션을 이용하면 웹 레이어 테스트를 하는 데 필요한 @Controller, @ControllerAdvice, Filter 등만 Bean으로 등록된다.
예시 코드
@ExtendWith(SpringExtension.class)
@WebMvcTest(UserController.class)
public class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private UserService userService;
@Test
void shouldReturnUser() throws Exception {
// Given
Long userId = 1L;
UserDto mockUser = new UserDto(userId, "John Doe", "john@example.com");
when(userService.getUserById(userId)).thenReturn(mockUser);
// When & Then
mockMvc.perform(get("/users/{id}", userId))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value("John Doe"))
.andExpect(jsonPath("$.email").value("john@example.com"));
}
}MockMvc를 사용하여 위처럼 REST API를 실제로 호출하는 것처럼 테스트 가능하다.
@MockBean
위 예시 코드에서 UserService는 왜 @Mock이 아닌 @MockBean으로 등록되었을까?
위 코드는 Web Layer 내 Spring Bean과의 연동을 테스트하는 것이므로 Service 객체도 일반 Mock 객체가 아닌 Spring Bean인 Mock 객체가 필요하다. 따라서 @MockBean으로 Spring Bean인 Mock 객체를 주입한 것이다.
📌 Repository Layer Test
✅ JPA 관련 Bean(@Repository)만 로드하여 테스트
예시 코드
@DataJpaTest
public class UserRepositoryTest {
@Autowired
private UserRepository userRepository;
@Test
void 멤버_저장_테스트() {
// given
String name = "choi";
String nickname = "phillip";
Member member = Member.of(name, nickname);
// when
myJpaRepository.save(member);
Optional<Member> foundResult = myJpaRepository.findById(1L);
// then
assertSoftly(softly -> {
softly.assertThat(foundResult)
.isNotEmpty();
Member foundMember = foundResult.get();
softly.assertThat(foundMember.getName()).isEqualTo(name);
softly.assertThat(foundMember.getNickname()).isEqualTo(nickname);
});
}
}@DataJpaTest를 사용하면 기본적으로 인메모리 데이터베이스인 H2를 기반으로 테스트용 데이터베이스를 구축한다. 또한 테스트가 끝나면 롤백을 해준다.
레포지토리 계층은 실제 DB와 통신 없이 Mock 객체를 사용하는 것이 의미가 없기 때문에 직접 DB와 통신하는 @DataJpaTest를 사용해야 한다.
📌 참고
https://jojoldu.tistory.com/226
https://tecoble.techcourse.co.kr/post/2021-05-18-slice-test/
https://mangkyu.tistory.com/145