티스토리 뷰

Spring

[Spring] @WebMvcTest와 @MockBean에 의한 테스트 성능 문제 해결을 위한 커스텀 라이브러리 구현 및 소개(feat. AutoMock)

망나니개발자 2022. 5. 30. 10:00
반응형

이번에는 @WebMvcTest가 갖는 한계와 이를 극복하기 위해 직접 개발해본 라이브러리를 소개해보고자 합니다. 매우 초기 버전인만큼 어떠한 버그와 문제가 나올지 모르지만, 써보시고 이슈 등록이나 문제점 공유 등 해주시면 감사드리겠습니다!

 

 

 

1. 커스텀 라이브러리 구현(feat. AutoMock)


[ 요구사항 ]

앞선 포스팅에서 @WebMvcTest가 갖는 한계점들을 알아보았다. 그리고 이러한 문제를 해결하고자 직접 커스텀 라이브러리를 구현하고자 하였는데, 개인적으로 작성한 요구사항은 다음과 같다.

  1. @WebMvcTest를 사용할 것
  2. @MockBean과 @SpyBean을 사용하지 않고 가짜 객체를 지원할 것
  3. 애플리케이션 컨텍스트를 재사용할 것

 

 

1. @WebMvcTest를 사용하여 설정을 자동화할 것

@WebMvcTest를 사용했을 때의 장점 중 하나가 웹 계층 설정 자동화이다. 웹 계층 설정이 자동화 되어야만 웹 계층에 대한 설정이 변경되어도 추가적인 비용 없이 테스트 코드를 유지할 수 있다.

 

 

2. @MockBean과 @SpyBean을 사용하지 않고 가짜 객체를 지원할 것

@MockBean과 @SpyBean은 애플리케이션 컨텍스트를 새롭게 만들도록 하는 요인 중 하나이다. 그러므로 @MockBean과 @SpyBean을 사용하지 않고도 가짜 객체를 사용할 수 있어야 한다.

 

 

3. 애플리케이션 컨텍스트를 재사용할 것

@WebMvcTest가 느려지는 이유는 결국 애플리케이션 컨텍스트가 계속 새롭게 만들어지기 때문이다. 그러므로 모든 컨트롤러 테스트마다 애플리케이션 컨텍스트를 재사용해야만 테스트 속도를 증가시킬 수 있다.

 

 

 

 

 

[ 구현 방법 및 동작 과정 ]

직접 구현한 라이브러리의 이름은 자동으로 mock 객체를 만들어준다는 점에서 AutoMock으로 지었고, 동작 과정은 다음과 같다.

  1. ApplicationPreparedEvent 이벤트를 수신함
  2. 개발자가 직접 구현한 빈들만 필터링함
  3. 해당 빈들이 의존하는 객체가 존재하지 않는 경우 mock 객체로 빈 등록함
  4. 애플리케이션 컨텍스트가 @WebMvcTest로 스캔한 빈들을 생성함

 

 

1. ApplicationPreparedEvent 이벤트를 수신함

ApplicationPreparedEvent는 애플리케이션 컨텍스트가 생성된 바로 직후에 발행되는 이벤트이다. 해당 이벤트가 발행되면 AutoMock을 적용할 패키지를 지정한다. properties에서 설정이 가능하며 설정이 없으면 메인 클래스의 패키지를 기준으로 삼는다.

 

 

 

2. 개발자가 직접 구현한 빈들만을 필터링함

애플리케이션 컨텍스트에는 개발자가 구현한 빈들도 등록이 되지만 스프링이 등록하는 빈들도 많이 등록된다. 그 중에서 개발자가 구현한 빈들만을 찾아내서 @WebMvcTest에 의해 스캔되지 않은 빈들을 찾아야한다. 예를 들어 개발자가 추가한 컨트롤러 클래스를 찾아야 해당 컨트롤러가 의존하는 서비스 클래스들을 찾을 수 있기 때문이다.

 

 

 

3. 해당 빈들이 의존하는 객체가 존재하지 않는 경우 mock 객체로 빈 등록함

이제 개발자가 구현한 빈들을 대상으로 해당 빈들이 의존하는 빈들을 찾는다. 그리고 의존하는 빈이 애플리케이션 컨텍스트에 존재하지 않으면 automock 적용 대상이라고 인식하고 mock 객체를 생성해서 애플리케이션 컨텍스트에 등록해준다.

현재는 @WebMvcTest에 의해 스캔된 @RestController와 같은 객체들이 만들어지기 전이다. 해당 클래스들이 의존하는 빈들이 존재해야 의존하는 빈을 주입하여 객체 생성이 가능하기 때문이다. 그렇지 않으면 컨트롤러가 의존하는 객체가 존재하지 않아 에러가 발생한다.

 

 

 

4. 애플리케이션 컨텍스트가 @WebMvcTest로 스캔한 빈들을 생성함

이제 @WebMvcTest에 의해 스캔된 빈들이 의존하는 객체들을 모두 애플리케이션 컨텍스트에 등록되었으므로 해당 빈들을 객체로 만들 수 있다. 애플리케이션 컨텍스트가 모든 빈들을 생성하면 테스트를 위한 준비가 마무리된 것이다.

 

 

 

 

 

2. 커스텀 라이브러리(feat. AutoMock) 사용해보기


[ AutoMock 사용 방법과 적용 코드 ]

AutoMock 사용 방법

해당 라이브러리는 maven 저장소에 배포되어 있으므로 먼저 다음과 같이 의존성을 추가해야 한다.

testImplementation 'io.github.mangkyu:spring-boot-test-automock:0.0.4'

 

 

그리고 해당 기능을 활성화하기 위해 아래의 enable을 프로퍼티에 반드시 추가해주어야 한다.

io.github.mangkyu.automock.enable=true

 

 

모킹할 대상 클래스는 메인 클래스를 기준으로 진행된다. 만약 이를 변경해주고 싶다면 아래와 같이 지정해주면 된다.

io.github.mangkyu.automock.target.basepackage=io.github.mangkyu

 

 

 

AutoMock 적용 코드

의존성을 추가해주는 것 외에 추가해적으로 해줘야하는 것은 없다. AutoMock을 적용하면 테스트 코드를 다음과 같이 작성할 수 있다. 기존에는 @MockBean을 사용해야 했다면 @Autowired를 이용해 mock된 빈을 주입받을 수 있다.

@WebMvcTest
class MemberControllerTest {

    @Autowired
    private MemberService memberService;
    
    @Autowired
    private MockMvc mockMvc;

}

 

 

실제로 컨트롤러 테스트에 대한 실행 기록을 살펴보면 애플리케이션 컨텍스트가 매번 새롭게 만들어지는 것이 아니라 재사용됨을 확인할 수 있다. 또한 이로 인해 테스트 속도 역시 빨라짐을 확인할 수 있다.

 

 

 

[ 주의 사항 ]

  1. AutoMock은 Spy가 아닌 Mock 기반으로만 가짜 객체를 생성함
  2. AutoMock은 생성자를 기반으로만 의존하는 객체를 생성함
  3. 특정 컨트롤러를 @WebMvcTest에 특정하지 않아야 함

 

컨트롤러 테스트에서 @Spy가 필요로 하는 케이스가 거의 없었던 것 같아서 현재는 Mock으로만 가짜 객체를 생성하고 있다. 또한 @WebMvcTest에 의한 문제를 개선하고자 할 정도면 이미 생성자 주입을 기반으로 구현하고 있을 것이다. 그러므로 생성자 기반으로 의존 객체를 생성하도록 되어 있다. 마지막으로 @WebMvcTest에 특정 컨트롤러를 지정하는 것은 해당 컨트롤러만 애플리케이션 컨텍스트에 등록되게 하므로 새로운 컨텍스트 생성을 필요로 한다. 그러므로 @WebMvcTest에 특정 컨트롤러를 지정해서는 안된다. 이러한 이유로 특정 컨트롤러 테스트에서 다른 컨트롤러의 API도 호출이 가능하다.

 

 

 

 

매우 초기 버전의 프로젝트이라서 적용 후에 다양한 이슈들이 등장할 것입니다. 그럼에도 불구하고 좋은 오픈소스로 발전하기 위해 토이 프로젝트에 사용해보시고 이슈 등록이나 문제점 공유 등 해주시면 감사드리겠습니다!

깃 주소: https://github.com/MangKyu/spring-boot-test-automock

 

 

 

 

반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG more
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함