[Spring boot] Spring 테스트 방법과 @SpringBootTest

반응형

서버 애플리케이션에서는 테스트 코드를 어떻게 구현해야 할까요?

 

제가 처음 서버 애플리케이션을 개발하고 나서 테스트 코드를 구현했을 때 가장 큰 의문점이 들었던 유형이었습니다. 클라이언트 개발로 안드로이드 개발을 진행했을 때는 Unit Test와 Instrument Test 두 가지를 진행했고, 각각 DB I/O 테스트와 UI/UX 동작 테스트를 진행한 것이었습니다.

 

그렇다면 서버 애플리케이션은 어떨까요? 대표적인 Spring boot를 이번 포스트에서 다뤄볼텐데, Spring boot에서는 JUnit 이라는 테스트 도구와 Mockito라는 Mock 객체 생성 라이브러리를 이용하여 테스트를 진행할 수 있고, 테스트 방법에 따라서 3가지로 분류할 수 있습니다.

 

 

 

Spring boot의 테스트 분류

https://spring.io/guides/gs/testing-web/

 

Testing the Web Layer

this guide is designed to get you productive as quickly as possible and using the latest Spring project releases and techniques as recommended by the Spring team

spring.io

공식 Spring에서 가이드하는 테스트 방법을 보면, Web Layer(Controller)만을 테스트하는 @WebMvcTest와 애플리케이션 전체를 로드하여 진행하는 @SpringBootTest를 볼 수 있었습니다. 

 

  • WebMvcTest

    WebMvcTest는 Controller(API) Layer만을 테스트하기 적합한 테스트 어노테이션으로 전체 애플리케이션을 실행하는 것이 아닌 Controller만을 로드하여 테스트를 진행할 수 있는 아주 일목요연한 테스트 방법

  • SpringBootTest

    SpringBootTest는 실제 애플리케이션을 자신의 로컬 위에 올려서 포트 주소가 Listening 되어지고, 실제 Database와 커넥션이 붙어지는 상태에서 진행되는 Live 테스트 방법

언뜻보면 두 테스트간의 차이는 전체 애플리케이션을 띄운다는 점과 일부 Controller만을 띄운다는 점으로 보여지는데, 목적으로만 본다면 이 점이 가장 핵심이며 애플리케이션의 규모가 커지게 되는 경우 테스트 시간이 그만큼 길어지기 때문에 신규 기능이나 버그 패치 등 일부 기능만을 테스트하고자 할 떄는 WebMvcTest가 적당하다고 볼 수 있습니다.

 

이 외에도 Data I/O만을 테스트할 수 있는 방법도 존재합니다.

 

https://docs.spring.io/spring-boot/docs/1.4.2.RELEASE/reference/html/boot-features-testing.html

 

40. Testing

A few test utility classes are packaged as part of spring-boot that are generally useful when testing your application. TestRestTemplate is a convenience alternative to Spring’s RestTemplate that is useful in integration tests. You can get a vanilla temp

docs.spring.io

애플리케이션에서 DB의 연결을 Spring Data JPA로 하고 있다면 DataJpaTest는 이에 적합한 선택입니다. 애플리케이션을 직접실행하지 않고, Transaction 코드와 EntityManager만을 이용해 Database의 트랜잭션이 잘되는지를 보기 위한 전용 테스트입니다.

 

 

 

How to use

더 자세한 이야기는 다음 포스트에서 다뤄볼 예정이지만 간단히 사용할 수 있는 방법에 대해 알아보겠습니다.

testImplementation('org.springframework.boot:spring-boot-starter-test') {
    exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}

gradle에서 Spring boot test 모듈을 추가해줍니다.

 

기본적으로 Spring boot에서 만들어주는 테스트 코드는 위와 같습니다. @SpringBootTest는 위에서 말했던대로 애플리케이션을 직접 구동해서 테스트를 진행하는 라이브 테스트 방법입니다. 따라서 사용할 Controller(API)를 만든 다음 이를 테스트 코드에 의존성 주입했을 때 정상적으로 구동되는지 확인해보겠습니다.

 

페이지에 hello를 출력해주는 HelloController를 한 개 만들어줍니다.

 

그런 다음 HelloController를 IoC에서 주입받는 형태로 코드를 구현한 다음 이것이 제대로 받아지는지를 확인하는 테스트 코드를 작성합니다. (@SpringbootTest가 정말로 컨텍스트를 올려서 모든 빈을 가져오는지를 보기 위함입니다.)

실행해보면, 정상적으로 동작하고 있음을 볼 수 있습니다.

 

더 나아가서 PORT 주소를 8080(기본값)이 아닌 무작위한 포트 주소로 설정하여 테스트 범위를 넓혀볼 수 있고, Controller의 함수가 잘 동작하는지를 볼 수 있습니다.

 

 

 

정리

간단하게 @SpringBootTest로 애플리케이션의 테스트를 진행하는 방법에 대해 알아봤습니다. @SpringBootTest는 스프링 애플리케이션의 통합 테스트를 제공하는 기본적인 Spring boot 어노테이션으로 애플리케이션 자체의 설정을 바꿔가거나 Properties를 임의로 만드는 등 애플리케이션의 전역 설정을 진행하면서 여러 단위 테스트를 하나로 묶어 놓은 애플리케이션 전체 테스트 방법입니다.

 

종류 요약 Bean 범위
@SpringBootTest 전체 테스트 어노테이션 애플리케이션에 주입된 Bean 전체
@WebMvcTest Controller Layer 테스트 MVC 관련 Bean (Controller, Service)
@DataJpaTest Jpa (DB I/O) 테스트 JPA 관련 Bean (EntityManager)
@RestClientTest Rest API 테스트 RestTemplate 등 일부 Bean
@JsonTest Json 데이터 테스트 Json 관련 일부 Bean

 

간단하게 놓고 보면, @SpringBootTest는 애플리케이션의 전체 Bean을 모두 가져오고, 그렇지 않은 4개의 어노테이션은 테스트를 위한 일부 Bean을 엔지니어가 지정해서 가져오는 것이라고 보면 됩니다. 다만 어노테이션별로 그들만이 사용할 수 있는 템플릿을 제공해줌으로써 더 쉽게 사용할 수 있습니다.

 

이 외에도 Spring WebFlux를 사용하는 경우에는 WebFluxTest가 별도로 존재하지만 이는 차후 WebFlux를 다룬 이후에 별도로 다뤄보는 것으로 진행하겠습니다.

 

 

 

마치며...

간단히 @SpringBootTest가 어떤식으로 진행되는지를 알아봤습니다. 애플리케이션 전체를 로드하여 전체적인 테스트를 진행하면 다른 테스트는 의미가 없지 않을까 라는 생각을 가지고 있었지만 단위별로 테스트를 진행함으로써 테스트 시간을 줄이고, 불필요한 리소스를 제외시킴으로써 개발 시간을 단축시키는 것은 매우 중요하다고 봅니다.

 

특히 Spring 애플리케이션은 간단한 마이크로서비스보다는 모놀리스의 커다란 애플리케이션들도 포함될 수 있는데, 만약 단위 테스트를 위해 전체 테스트인 @SpringBootTest를 이용한다면 모든 Bean이 다 로드되기 때문에 JVM에서 이 인스턴스를 생성하고 Heap에 할당하는 데까지 많은 시간이 소요되므로 테스트 비용을 줄이고자 한다면 이 방법을 권장드리진 않습니다.

 

다음 포스트에서는 @WebMvcTest로 테스트 코드를 구현하는 방법에 대해 알아보도록 하겠습니다.

반응형