Spring

슬라이스 테스트를 하게 된 이유

leeheefull 2022. 3. 18. 17:10

테스트하는 이유

 

개발자라면 때때로 기능을 구현하고 나서 실행을 했을 때, 에러가 발생할 때가 있을 겁니다. 에러를 잡는데 짧은 시간이 걸릴 때도 있지만, 오랜 시간이 걸리기도 합니다. 특히, 저 같은 초급 개발자라면 경험이 부족하기 때문에 더욱 오래 걸릴 거라고 생각합니다.

 

에러를 잡는데 오랜 시간이 걸린 적이 많았고, 정말 사소하고 간단한 부분을 잘못해서 발생한 문제를 오랜 시간 동안 고민하여 해결한 적도 있습니다.

 

테스트 코드를 짜는 이유는 많지만, 저는 이러한 점을 해결하기 위해서 테스트 코드가 꼭 필요하다고 생각했습니다.

 

본인이 새롭게 작성한 코드마다 테스트를 진행하게 된다면, 적어도 기능이 완성됐을 때의 에러가 나의 코드로 인한 문제가 아닌 설정 등과 같은 외부 요인에서 발생한 문제라는 것을 알게 될 겁니다. 이것만 알게 되어도 정말 빠르게 에러를 캐치할 수 있다고 생각합니다.

 

평소에 일반적인 Java 프로그램은 테스트를 해봤지만, 스프링 프레임워크 기반 프로젝트를 테스트해본 적은 없었습니다. 이번 기회에 스프링 프로젝트 테스트해보게 됐습니다. 스프링 테스트를 하면서 제가 느꼈던 문제점에 대해 설명하고 해결방법을 제시해 보는 시간을 갖겠습니다.

 

 

 

너무 느린 테스트 속도

 

스프링 프로젝트를 테스트하기 위해서는 @SpringBootTest를 사용합니다. 스프링 프로젝트는 실행할 때 모든 빈을 로드합니다. 테스트를 할 때도 모든 빈을 로드해야 하는데, 다행히도 해당 어노테이션을 사용하면, 이를 해결해 줍니다.

 

하지만, 단순히 메서드 하나를 테스트할 때도 스프링 빈을 전부 다시 로드한다면 시간이 오래 걸리게 문제가 생길 겁니다.

 

통합 테스트라면 괜찮겠지만, 단위 테스트는 빠르고 신속해야 한다고 생각합니다. 기능을 구현하면서 즉각적인 테스트를 하며 검증을 해야 하기 때문에, 매번 테스트할 때마다 시간이 걸린다면, 테스트의 장점을 잃어버린다는 생각이 들었습니다.

 

스프링 빈을 모두 로드하지 않고 테스트하는 방법이 없을까요?

 

 

 

길어지는 Given 단계

 

https://user-images.githubusercontent.com/58816862/158951965-fc672388-179d-43c6-bac8-88df083d5e7b.png

 

단순히 게시글을 조회하는 메서드를 테스트한다고 할 때, 회원 정보와 게시판 정보, 게시글 정보의 세팅이 필요합니다. 게시글은 물론이고, 회원 정보를 통해서 정보를 저장하고 게시판 정보를 통해서 정보를 저장해야 합니다.

 

우리가 테스트하고 싶은 것은 게시글 서비스의 게시글 조회 메서드지만, 이것을 테스트하기 위해 필요한 정보를 모두 세팅해줘야 합니다. 만약, 복잡한 로직이라면 given 단계는 얼마나 더 길어질까요?

 

테스트 코드 또한 가독성이 좋아야 합니다. 테스트 코드는 테스트 목적 이외에도 해당 매서드가 어떤 기능을 하는지 직관적으로 확인할 수 있어야 합니다.

 

테스트 대상 코드를 테스트하는데 정말 필요한 객체가 있는 반면, 게시판과 회원 정보처럼 테스트에 필요 없는 정보가 있습니다. 정말 필요한 객체만 테스트에 참여할 수는 없을까요?

 

 

 

슬라이스 테스트

 

위 두 가지 문제점을 해결하기 위해서 도입된 개념이 슬라이스 테스트입니다.

 

슬라이스 테스트란 각 레이어를 독립적으로 테스트하는 것을 말합니다. 슬라이스 테스트를 하기 위한 어노테이션과 Mockito라는 라이브러리가 있습니다. 이들을 적절히 사용하여 각 레이어를 독립적으로 테스트할 수 있습니다.

 

 

다음은 슬라이스 테스트를 하기 위한 대표적인 어노테이션입니다.

 

  • @WebMvcTest
  • @DataJpaTest
  • @WebFluxTest
  • @JsonTest
  • @RestClientTest

사용법이 간단하기 때문에 하나씩 확인해 보면서 사용해보면 좋을 것 같습니다.

 

 

 

Mockito

 

위의 설명에서 게시글을 조회하기 위해서는 여러 가지 세팅을 해줘야 한다고 했는데, 모키토를 이용하면 테스트 대상에 주입되는 객체들을 가상으로 주입할 수 있어서 간편하게 테스트할 수 있습니다.

 

 

https://user-images.githubusercontent.com/58816862/158952423-e18bab04-4da9-47ee-802f-d2f151c5bd0d.png

 

위처럼 간편하게 테스트 객체에 필요한 정보들을 모의 객체로 생성하여 테스트 대상 객체에 주입할 수 있습니다. 이처럼 모의 객체를 주입하기 때문에 각 레이어의 독립적인 테스트가 가능하게 됩니다. 그렇다면 테스트 대상 객체의 메서드에서는 모의 객체의 메서드에 대해서 어떻게 알까요

 

 

https://user-images.githubusercontent.com/58816862/158951110-54cd7ef9-75fa-411c-9408-1aa65646b990.png

 

목킹을 통해서 테스트 대상 객체의 메서드에서 사용하고 있는 협력 객체의 메서드를 정의합니다.

 

@Mock으로 선언된 협력 객체들은 어떻게 보면 무늬만 있는 빈 깡통 객체라고 할 수 있습니다. 목킹을 통해서 사용할 메서드에 대해 정의해주면 간편하게 사용할 수 있게 됩니다.

 

모키토에는 @Mock 말고도 @MockBean, @Spy, @SpyBean 등이 있고 목킹의 방법에도 여러 가지가 있습니다. 또한, 컨트롤러에서의 목 객체 주입 방법도 다릅니다. 자세한 사용법은 여기를 추천합니다!! 사용법 관련해서 예제를 참고하고 싶으시다면, 여기를 참고해주시면 좋겠습니다.

 

 

이처럼 각 레이어의 독립적인 테스트를 진행하면 기능 구현과 동시에 테스트를 하기에 간편해집니다. 스프링 설정을 따로 해 줄 필요도 없을뿐더러, DB 연결도 필요 없고, 테스트할 때마다 빈을 로드하지 않아도 되어 빠른 속도로 테스트를 할 수 있게 됐습니다. 또한, 테스트할 때 불필요한 정보들이 줄어들면서 테스트 코드의 가독성이 올라가게 됐습니다.

 

하지만, 저는 아직도 현재 테스트의 문제점이 있다고 생각했습니다. given 단계에서 항상 똑같은 값을 테스트하는 것과 값을 직접 바인딩하는 것을 개선해야겠다고 생각했습니다. 그래서 Fixture monkey라는 라이브러리를 사용하게 됐습니다.

 

 

 

Fixture monkey에 대한 설명은 다음 포스팅에서 자세한 설명을 하겠습니다. 이상입니다. 수정 사항이나 피드백이 있으시다면 편하게 댓글 부탁드리겠습니다. 글 읽어 주셔서 감사합니다