-
Spring Boot Test - 1. 기본개념Computer - Server 관련/Spring boot 2023. 1. 15. 17:45
일반 Java application에서의 Test module로는 JUnit 5와 AssertJ가 있는 것처럼, Spring Boot에서도 테스트 환경을 만들 수 있고, Http 요청에 따라 어떻게 반환하는지(header에 특정 값이 있는지, body가 어떠한지 등등...) 또한 테스트 할 수 있다.
1. 테스트 환경 만들기
당연하게도 JUnit5와 AssertJ만을 써서 Assertions.assertThat(~~).~~를 써서 테스트 할 수도 있지만, 이것만 쓴다면 서버를 구동시키고 서버에 요청을 보내고 받아오고 헤더 분리하고 바디 분리하고... 하는 게 굉장히 힘들 것이다.
그래서 Spring Boot에서는 테스트 환경을 조성할 수 있는 여러 모듈을 제공하는데, 일단 기본적인 건 한줄만 클래스 선언부에 적으면 된다.
"@SpringBootTest" 이 한줄 만으로 기본적인 것은 조성이 된다. 다르게 말하면, 스프링에서 이 한 줄 만으로 Spring에서 선언한 컴포넌트들을 모두 사용할 수 있는 것 뿐만 아니라 mock servlet environment(가짜 서버) 혹은 실제 서버를 구동시켜서 테스트를 할 수 있다. SpringBootTest에 webEnvironment = ~~로 실제 서버 환경, 가짜 서버(mock), 혹은 서버 환경을 아예 배제할 것인지 지정할 수 있다.
속성 값 무슨 일을 하는고? WebEnvironment.DEFINED_PORT 서버를 열 포트를 지정할 수 있다.
각각의 테스트가 멀티스레드 환경에서 동작하며, Transactional이 동작하지 않는다. 다르게 말하면, DB 등 외부 리소스를 활용하는 경우 각 테스트 메소드마다 격리성이 보장되지 않는다.WebEnvironment.RANDOM_PORT 랜덤으로 가능한 port로 서버를 열어서 테스트한다. 이 때, 포트 정보는
@LocalServerPort
int port;
를 하여 포트에 대한 정보를 받아올 수 있다.
후술할 RestAssured에서는 반드시 RAMDOM_PORT를 지정하고 BeforeEach에서 포트정보를 RestAssured에 지정해 주어야 한다.
DEFINED_PORT와 마찬가지로 각각의 테스트가 멀티스레드 환경에서 동작하며, Transactional이 동작하지 않는다. 다르게 말하면, DB 등 외부 리소스를 활용하는 경우 각 테스트 메소드마다 격리성이 보장되지 않는다.WebEnvironment.MOCK 가짜 서버 환경을 만들어서 테스트한다.
아래와 같이 @AutoConfigureMockMvc와 @Autowired로 mockMvc에 대한 정보를 Spring에서 자동으로 주입하도록 하거나, 혹은 특정 클래스만을 mock로 만들어서 가볍게 테스트 할 수도 있다.
RestAssuredMockMvc를 사용하는 경우 mock에 대한 정보를 가진 mockMvc를 RestAssuredMockMvc에 수동으로 주입해 주어야 한다.
WebEnvironment.NONE 웹 환경을 만들지 않고 ApplicationContext만을 로드한다.
예시로 Controller가 아닌 Service, Repository를 테스트할 경우 웹 요청을 보내지 않아도 되기 때문에 굳이 웹 환경을 만들지 않아도 된다 - 물론 이 경우 단위테스트를 하는 게 더 좋을 수도 있지만..자세한건 여기에서 조금 더 찾아보자.
https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.testing
물론, @SpringBootTest 뿐만 있는 것이 아니라 @WebMvcTest 등 수많은 단위 테스트용 모듈이 있다. 이들은 ApplicationContext에 있는 Bean 중 일부만을 로드하는 등(@WebMvcTest의 경우 Controller 및 ControllerAdvice와 같은 관련 클래스만 로드함) SpringBootTest에 비해 가볍게 테스트할 수 있도록 설계된 것들이다.
2. MockMvc, RestAssured, RestAssuredMockMvc로 테스트 코드 작성
위와 같이 테스트 환경을 만들었으면 테스트를 해야 한다. 당연하게 AssertJ를 이용한 것들도 가능하나, 조금은 웹에 특화된 친구들이 존재한다. 대표적으로 많이 보이는 것들이 MockMvc, RestAssured이다.
MockMvc는 build.gradle(혹은 pom.xml)에 org.springframework.boot:spring-boot-starter-test로 의존성을 추가하면 자동으로 딸려오기 때문에 가볍다. 다만 테스트 코드가 RestAssured에 비해 조금 번잡스럽다.
RestAssured는 MockMvc와는 다르게 spring-boot-starter-test에 포함되어 있지 않다. 따라서 아래와 같이 추가로 의존성을 추가해주어야 한다.
testImplementation 'io.rest-assured:rest-assured:4.4.0'
게다가 위에서 언급한 대로 RANDOM_PORT 환경에서 동작하기에 테스트 자체가 상대적으로 무거워진다.
하지만 가독성이 굉장히 좋다.따라서 RestAssured는 통합 테스트에서 많이 활용된다고 한다.
RestAssured에서도 Mock 환경에서 동작할 수 있도록 RestAssuredMockMvc를 따로 제공한다.
testImplementation 'io.rest-assured:spring-mock-mvc'
위와 같이 build.gradle에 의존성을 추가한 뒤, 다음과 같이 MockMvc에 대한 정보를 RestAssuredMockMvc에 주입하면 위의 given() ~ when() ~ then()을 테스트 메소드마다 그대로 쓸 수 있다.
RestAssuredMockMvc는 의존성을 따로 추가해주어야 한다는 단점은 가지고 있지만, Mock환경에서 동작한다는 점, 테스트 소스가 깔끔하다는 점에서 MockMvc와 RestAssured의 장점을 모두 가진다고 볼 수 있겠다.
RestAssured를 어떻게 사용하는지에 대해서는 다음 사이트를 참조하면 좋다.
https://github.com/rest-assured/rest-assured/wiki/Usage
각각의 모듈로 어떻게 작성하는지에 대해서 여기에 작성하면 너무 길어질 것 같아 일단 여기서 글을 줄이겠다.