Spring REST Docs - 2

TunaHG·2023년 4월 9일
0

Spring REST Docs 작성을 위한 ControllerTest를 단위테스트로 변경했던 과정을 돌아본다.

통합테스트 vs 단위테스트

통합 테스트

큰 동작을 달성하기 위해 여러 모듈들을 모아 이들이 의도대로 협력하는지 확인하는 테스트
개발자가 변경할 수 없는 부분(외부 라이브러리)까지 묶어서 검증할 때 사용한다.

보통 Spring Boot에서는 SQL을 활용하여 테스트데이터를 넣어두고, API를 호출하여 원하는 응답을 받는지 테스트해본다. Coontroller - Service - Repository 등의 모든 Class에 실제 객체를 사용하여 테스트한다.

단위 테스트

응용 프로그램에서 테스트 가능한 가장 작은 소프트웨어를 실행하여 예상대로 동작하는지 확인하는 테스트

보통 Spring Boot에서는 Controller, Service, Repository 등 각각의 Class들에 한정되어 테스트한다. 해당 Class에 필요한 다른 객체들은 Mock 등을 활용하여 가짜 객체를 사용하여 테스트한다.

당시 Spring REST Docs를 위한 Test

@SpringBootTest를 사용하는 통합테스트로 진행중이였다.
MockMvc를 활용해 API를 호출하고 API의 전체 동작(Controller, Service, Repository, ...)이 성공하면 REST Docs를 작성했다.

통합테스트로 진행한 방식의 문제점

  • API Docs의 배포 시간이 오래걸린다.
    @SpringBootTest로 각 테스트마다 Context를 전부 띄워서 진행하니 테스트 시간이 오래걸린다.
  • DB와의 연동 문제
    당시 테스트에 개발DB를 활용했었는데, 개발 DB에 여러 데이터가 들어가있다보니 값이 변동되면 테스트가 실패할 수 있다.
  • Wechat 로그인 문제
    당시 Wechat 로그인을 구현할때, Callback Domain을 하나만 지정할 수 있어서 운영배포를 위한 운영도메인을 사용해야했는데 기존 테스트는 개발환경으로 지정되어 있어서 오류가 발생했다.

단위테스트로의 변경

첫번째 시도

처음에는 Context 띄우는 시간을 줄이기 위해 @SpringBootTest@WebMvcTest로 변경하고자 했다.

@WebMvcTest는 많은 Spring REST Docs 참고자료들이 진행하고 있는 방법이기도 하며, MVC를 위한 테스트로 컨트롤러가 예상대로 동작하는지 테스트하는데 사용된다.

@WebMvcTest는 다음 Bean들만 스캔하도록 제한한다.

해당 시도는 다른 테스트에 필요한 Spring Config들을 불러오지 못해서 에러가 발생했다.

두번째 시도

@SpringBootTest로 진행하되, 외부 API 및 DB와의 의존도를 제거한다.

당시 통합테스트 진행중 시간이 가장 오래걸린 것중 하나는 DB와의 의존도였다. DB의 형상관리를 위해 liquibase를 사용중이였는데, 통합테스트로 모든 Context를 띄우면 liquibase 로딩이 진행되서 시간이 오래걸린다는 점이였다.

@MockBean을 활용하여 서비스 객체를 가짜 객체로 선언하여 서비스 로직의 결과값을 원하는대로 제어했다. 가짜 객체로 선언되었기 때문에 서비스 로직을 실행하지 않아서 DB와의 의존도가 줄어된다.

서비스의 Authorization 문제는 Interceptor를 Bean처리 진행하고 나서 Test에서 MockBean으로 Interceptor의 행동을 제어하고 Context를 임의로 지정했다. 이로 인해 외부 API를 요청하던 주된 요인인 액세스토큰의 의존도를 제거했다.

하지만 위의 방법들로 인해 테스트를 진행하는 속도는 빨라졌지만, @SpringBootTest로 인해 Context를 띄워서 liquibase로 DB와의 Connection을 연결하는 과정에서 문제가 발생한다. 짧은시간내에 DB로 Connection이 너무 많이 요청되어 Too many Connectino 에러가 발생한 것이다.

세번째 시도

그래서 결국 돌고 돌아 모든 Context를 띄우는 @SpringBootTest는 제거하고 MockitoExtension만 활용하는 단위테스트로 변경했다.

테스트를 진행하는 Controller에 @InjectMocks로 Mock들을 주입받을 변수임을 지정하고, 필요한 나머지 객체들에 @Mock을 선언하여 가짜 객체를 주입한다.

mockMvc 설정을 standaloneSetup()으로 진행하여 해당 Controller에 대한 테스트만 진행하도록 설정한다. ([Spring/번역] 컨트롤러 테스트 가이드 in Spring Boot)

테스트 상에서는 해당 API에서 실행되는 Service 등 객체들의 모든 메소드의 Return값을 설정해야 한다. - doReturn().when().someMethod();

에러 발생 테스트를 진행하기 위해 setControllerAdvice 추가했다.

발생했던 문제들과 해결방법

참고

profile
나태해지지 말자

0개의 댓글