[Spring] 통합 테스트 vs 슬라이스 테스트 (+ 개인적인 생각)

통합 테스트와 슬라이스 테스트 비교

이번에 통합 테스트와 슬라이스 테스트를 둘 다 적용해보며 직접 느낀점들을 작성하고자 한다.

이 글을 읽기 전에 주의할점은 계층별 슬라이스 테스트가 작성되어 있고, 통합 테스트까지 작성되어 있는 것과는 상관없다.

(테스트도 비용이기에 실제로도 규모가 큰 회사의 서비스에서 이렇게 까지 빡세게 작성할지는 모르겠지만...)

현재 프로젝트가 슬라이스 테스트로만 이뤄졌는지와 통합 테스트로만 이뤄졌는지에 대한 비교이다.

 

통합 테스트와 슬라이스 테스트가 무엇인지 알아보고 싶다면 아래 포스팅을 보고 오는 것을 추천한다.

2024.04.25 - [◼ JAVA/Spring] - [Spring] 스프링 테스트 어노테이션 알아보기 (feat. 슬라이스 테스트)

 

[Spring] 스프링 테스트 어노테이션 알아보기 (feat. 슬라이스 테스트)

웹 애플리케이션은 Controller, Service, Repository 계층이 있고 각 계층 별로 역할이 있다.스프링 테스트는 일전에 작성했던 경험이 없어 @SpringBootTest 어노테이션 밖에 몰랐는데Controller, Service, Repository

hstory0208.tistory.com

 

통합 테스트

 

장점

여러 계층이나 시스템이 실제로 어떻게 상호 작용하는지를 보여줘 실제 운영 환경에서 발생할 수 있는 문제를 더 잘 발견할 수 있다.

그렇기 때문에 다양한 구성 요소나 계층 간의 통합 문제를 신뢰도 있게 파악 가능하다.

 

단점

여러 구성 요소를 함께 테스트해야 하므로 스프링 컨테이너를 띄어 Bean들을 등록하고

톰캣도 띄우기 때문에 실행 시간이 길어질 수 있다.

 

슬라이스 테스트

 

장점

슬라이스 테스트는 톰캣을 실행하지 않고 대상이 되는 계층에서 필요한 Bean들만 등록해 테스트하기 때문에 실행 속도가 빠르다.

또한 특정 계층의 기능에 집중해 그 기능에 대해 세밀하게 파악할 수 있다.

 

단점

계층 간의 통합 문제나 Mock을 사용해 의존 관계를 끊고 테스트하기 때문에 실제 사용 환경을 완벽하게 모방하기 어렵다.

특히 필자는 서비스 계층에는 순수 비즈니스 로직만을 검증하기 위해 스프링 컨테이너를 전혀 띄우지 않는

@ExtendWith(MockitoExtension.class) 어노테이션을 사용했고,

@Mock과 @InjectMocks로 서비스 계층이 의존하는 Repository를 주입해 테스트 했었다.

이 경우 @Transactional 어노테이션으로 트랜잭션을 관리하는 서비스가 실제 DB의 커넥션을 들고 있지 않기 때문에

예외 발생시 정상적으로 데이터가 롤백됐는지도 확인할 수도 없다.

스프링 컨테이너를 사용하지 않기 때문에 서비스 계층에서 다형성이 적용된 빈을 주입받아 사용한다면 이 또한 검증이 어렵다.


슬라이스 테스트에서 통합 테스트로 바꾼 썰...

필자는 이번 우테코의 "방탈출 관리 시스템" 미션을 진행하면서 초기에는 학습차 슬라이스 테스트를 적용해보았었다.

재밌는게 모든 계층을 슬라이스 테스트로 작성했지만

점점 @SpringBootTest를 사용한 통합테스트로 리팩토링되어 가고 있었다... 😅

 

제일 첫 번째 리팩토링 대상은 서비스 계층이였다.

서비스 계층을 통합 테스트로 변경한 이유는 다음과 같았다.

필자의 서비스 계층은 스프링 컨테이너를 띄우지 않는 @ExtendWith(MockitoExtension.class) 어노테이션을 사용했었다.

서비스 계층은 애플리케이션에서 비즈니스 로직을 담당하고 있고, 이는 핵심이 되는 부분이라 생각한다.

하지만 이 핵심이 되는 계층을 Mock을 사용해 의존성을 끊고 테스트한다면 실제 환경과 달라지게 되는데 의미가 있을까?

스프링 컨테이너를 사용하지도 않았기에 위 슬라이스 테스트 단점으로 언급한 문제도 있었다.

결국 서비스 계층의 신뢰도가 중요하다고 생각이 들어 첫 번째 리팩토링 대상이 되었다 🤯

 

두 번째 리팩토링 대상은 컨트롤러 계층이다.

컨트롤러 계층의 경우에는 @WebMvcTest 어노테이션을 사용해 컨트롤러에 필요한 계층만 Bean등록하였고,

MockMvc로 웹 요청을 모의하여 테스트했다.

후반에 인증 관련 기능이 추가되면서 설정이 복잡해져 이 설정들을 적용시켜주기에는 복잡하기도 했고

특히 코드가 그렇게 가독성 있지도 않았다.
무엇보다 동일한 조건의 POST 요청에 대한 응답 테스트가 하나는 성공하고 하나는 실패하는 문제가 있었고

컨트롤러가 의존하는 서비스 계층이 실제 객체가 아닌 Mock이 였기에 원인 파악이 쉽지도 않았다.

결론만 얘기하자면 신뢰도가 떨어졌다.

결국 컨트롤러 계층도 통합 테스트 테스트 리팩토링 대상이 되었다 🤣

 

작성된 내용만 보면 슬라이스 테스트가 무조건 나쁘다고 느껴질 수 있다.

레포지토리 계층은 언급하지 않았는데 이 부분은 슬라이스 테스트를 적용했다.

요청에 대한 처리를 하는 계층에서 Controller - Service - Repository 제일 마지막에 위치한 계층이므로 

이 계층에서는 Repository와 관련된 Bean들만 등록하고 DB 커넥션을 연결해 테스트하는 것만으로도

충분히 신뢰도가 있다고 생각이 들었다.

 

Repository에는 슬라이스 테스트를 적용한 것과 같은 이유로

슬라이스 테스트도 장점도 있기에 적절하게 쓰인다면 좋다고 생각한다.

각 계층만의 로직이 있다면 그 로직만을 테스트 할 때는 속도가 빠른 슬라이스 테스트가 좋지 않을까?

이를 제외하고는 신뢰도가 높은 통합 테스트가 더 이점이 많다고 생각한다.