tools & libs/단위테스트(junit, spock)

[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관련 애너테이션들과 사용 시 자동으로 설정되는 환경들을 확인할 수 있다.

https://docs.spring.io/spring-boot/docs/current/reference/html/test-auto-configuration.html#appendix.test-auto-configuration

 

Test Auto-configuration Annotations

org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration org.springframework.boot.autocon

docs.spring.io

대표적으로 자주 사용되는 @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는 오류를 발생시킨다.

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.