[spring test] 1. spring과 junit
- -
최근에 Java를 이용한 웹 애플리케이션 프로젝트를 진행할 때는 Spring을 때 놓고 생각할 수 없다. JUnit에서는 Extension Model을 이용해서 다른 시스템과의 연결이 가능한데 연동이 되어야 Spring Framework와 소통하며 @Autowired등을 통해 빈을 사용할 수 있다.
이번 포스트에서는 Spring Framework와 JUnit을 연동하는 방법에 대해 살펴보자.
Spring Legacy Project와의 연동
먼저 spring legacy project에서의 설정 방법을 살펴보자.
의존성 설정
먼저 spring-test에 대한 의존성과 junit 이 필요하다.
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.18</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
테스트 클래스 작성
JUnit의 @ExtendWith는 Junit과 다른 프레임워크와의 연동을 지원한다. 당연히 @ExtendWith(SpringExtension.class)는 JUnit과 Spring을 연동하기 위해 사용되는 애너테이션이다. 이 둘이 연동되면 @Autowired 등 애너테이션을 테스트에서 사용할 수 있다. @ContextConfiguration을 이용해서설정 파일을 연결하면 로드된 빈은 injection 받아 사용할 수 있다.
import static org.junit.jupiter.api.Assertions.assertNotNull;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import com.ssafy.webex.config.ApplicationConfig;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = ApplicationConfig.class)
public class ApplicationTest {
@Autowired
ApplicationContext ctx;
@Test
public void testContext() {
assertNotNull(ctx);
}
}
SpringBoot Porject와의 연동
의존성 설정
spring boot에서는 spring-boot-starter-test에 의해 단위테스트 의존성이 설정되는데 테스트와 관련된 다양한 라이브러리가 포함되어있어서 추가로 구성할 내용은 거의 없다.
포함된 의존성들 | 역할 |
JUnit5 | 단위 테스팅 프레임워크 |
Spring Test & Spring Boot Test | Spring Boot Application에 대한 통합 테스트 및 지원 도구들 |
AssertJ | assertion을 위한 library |
Hamcrest | 값을 비교하기 위한 Matcher 객체들 |
JSONassert | JSON을 위한 assertion library |
JsonPath | JSON의 XPath 테스팅 도구 |
Awaitility | 비동기 시스템 테스팅 도구 |
기존 방식을 사용한 테스트
기본적으로 SpringBoot도 Spring이니까 Legacy에서 사용하던 방식 그대로 테스트가 가능하다.
import static org.junit.jupiter.api.Assertions.assertNotNull;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = DemoApplication.class)
public class PartTest {
@Autowired
ApplicationContext ctx;
@Test
void contextLoads() {
assertNotNull(ctx);
}
}
하지만 SpringBoot는 테스트에 대해서도 다양한 자동화 설정을 만들어두어 보다 편리하게 테스트를 진행할 수 있게 되었다.
@SpringBootTest
SpringBoot에서 단위테스트를 위해서는 @SpringBootTest를 사용할 수 있다. @SpringBootTest는 @SpringBootApplication 클래스를 이용해 ApplicationContext를 로딩하기 때문에 별도로 @ContextConfiguration을 추가할 필요는 없다.
import static org.junit.jupiter.api.Assertions.assertNotNull;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
@SpringBootTest
class DemoApplicationTests {
@Autowired
ApplicationContext ctx;
@Test
void contextLoads() {
assertNotNull(ctx);
}
}
매우 간편해졌는데 단점은 @SpringBootTest는 단위 테스트가 아니라 통합 테스트이기 때문에 일부분만 테스트하려는 상황에서 많은 부담이 된다. 예를들어 단순히 MVC의 URL을 처리하는 Controller를 테스트 하고 싶은데 Database까지 실행해야 하거나 반대로 JPA가 잘 동작하는지 테스트 해보고 싶은데 웹 계층까지 고려해야 한다면 속도도 매우 느려지고 테스트 실패의 원인을 분석하기도 어려워진다.
따라서 필요한 구성 부분들만 로딩해서 처리할 수 있게 해주는데 이런 형태의 테스트를 Slice Test라고 한다.
Slice Test
SpringBoot에서는 @XXTest 애너테이션을 이용해서 다양한 Slice Test를 지원한다. 다음페이지에서 Slice Test관련 애너테이션들과 사용 시 자동으로 설정되는 환경들을 확인할 수 있다.
대표적으로 자주 사용되는 @XXTest들은 다음과 같다.
- @WebMvcTest
- 웹과 관련된 동작을 테스트 하기 위해서 사용된다.
- @Controller, @ControllerAdvice, @JsonComponent, Converter, Filter, HandlerInterceptor등 웹과 관련된 빈을 스캔해서 등록한다.
- MockMvc 객체가 자동으로 구성되어 테스트가 용이하다(@SpringBootTest에서는 @AutoConfigureMockMvc 추가 필요)
- 추가적으로 필요한 설정이 있다면 @Import를 이용할 수 있다.
- @DataJpaTest
- @Entity와 Spring Data JPA Repository 타입의 빈들을 자동 구성한다.
- embedded database를 자동으로 구성하고 테스트에 사용할 수 있다.
- spring.jpa.show-sql 자동 설정으로 sql 문장을 로깅한다.
- 모든 테스트 마다 rollback이 자동으로 진행된다.
- 테스트를 위해 TestEntityManager를 주입받아서 사용할 수 있다.
- @RestClientTest
- RestTemplate등을 이용해서 원격의 서버와 통신하는 Service를 테스트 하기 위해 사용된다.
- RestTemplateBuilder, RestClient.Builder가 자동 주입 된다.
- 테스트에서 MockRestServiceServer를 이용해서 서버를 Mocking 할 수 있다.
- 테스트하려는 대상 빈은 value 또는 components 속성으로 지정할 수 있다.
아울러 로딩에서 제외된 빈에 대한 Mock이 필요한 경우는 @MockBean이나 @SpyBean을 사용한다.
spring boot 테스트 주의 사항?(기본 사항)
가끔 spring boot로 테스트 하는 과정에서 아래와 같은 오류를 만날 때가 있다.
java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration, you need to use
@ContextConfiguration or @SpringBootTest(classes=...) with your test
@SpringBootTest는 @SpringBootApplication이 붙은 클래스와 같은 패키지에 두어야 한다.
즉 좌측의 구조 처럼 @SpringBootApplication이 com.quietjun.junittest에 있을 때 com.quietjun.junittest.JunitApplicationTest는 정상적으로 동작하지만 mvc.JunitApplicationTest는 오류를 발생시킨다. |
'tools & libs > 단위테스트(junit, spock)' 카테고리의 다른 글
[spring test] 3. @Service Layer test (0) | 2023.11.27 |
---|---|
[spring test] 2. Spring Data Jpa Test (0) | 2023.11.27 |
[junit] jupiter 4. 가짜 객체를 활용한 테스트 (0) | 2023.11.23 |
[junit] jupiter 3. 단위테스트 작성 기법 (0) | 2023.11.23 |
[junit] jupiter 2. assertion (0) | 2023.11.23 |
소중한 공감 감사합니다