저번시간에 이어 오늘도 junit5 포스팅이다. 오늘은 junit5로 Spring을 어떻게 Test 하는지 알아보자. 이미 spring에서 만들어 놓아서 우리는 사용하기만 하면 된다. 일단 아래와 같이 maven 디펜더시를 받자.
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.0.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.0.1</version>
<scope>test</scope>
</dependency>
</dependencies>
간단하게 어떻게 하는지만 테스트를 할 예정이라 web과 관련된 설정은 하지 않았다. 그렇다고 웹이라고 해서 크게 다른 건 없다.
테스트를 위해 샘플 코드를 작성해보자.
public interface HelloService {
String hello();
}
@Configuration
public class Application {
@Bean
HelloService helloService() {
return () -> "hello world";
}
}
우리는 HelloService 라는 인터페이스를 빈으로 등록 하였다. 샘플 코드이기에 크게 의미는 없다.
저번시간에 배운 ParameterResolver 인터페이스를 구현한 Spring 의 코드가 존재한다. 바로
SpringExtension
클래스이다. 뿐만아니라 여러 인터페이스를 구현했으니 참고해도 되겠다. 우리는
SpringExtension
클래스를 사용해서 테스트를 할 것이다. 일단 한번 작성해보자.
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = Application.class)
class GeneralHelloServiceTests {
private final HelloService helloService;
@Autowired
GeneralHelloServiceTests(HelloService helloService) {
this.helloService = helloService;
}
@Test
void parametersHello(@Autowired HelloService helloService) {
assertEquals(helloService.hello(), "hello world");
}
@Test
void constructorHello() {
assertEquals(this.helloService.hello(), "hello world");
}
}
junit5의
ExtendWith
어노테이션을 사용해서 우리는 확장할 수 있었다. 또한 기존의
ContextConfiguration
어노테이션으로 컨텍스트를 설정 할 수 있었다.
SpringExtension
를 사용하면 생성자를 통해 빈을 주입 받을 수 있고 파라미터를 통해서도 빈을 주입 받을 수 있다. 하지만 여기서 주의할 점은 spring 4.3 부터는 일반적인 코드에는 생성자 위에 @Autowired를 붙이지 않아도 자동으로 주입하지만 테스트에서는 그렇지 않다. 무조건
@Autowired
를 작성해줘야한다. 물론 파라미터도 마찬가지다. 우리는 Spring에서 미리 만들어진의 junit5 지원으로 아주 심플하게 테스트를 할 수 있게 되었다.
이 보다 좀 더 간단하게 테스트 할 수 있는 방법이다. 간단하다고 하더라도 그냥 한줄 정도? Spring에서 지원해주는
@SpringJUnitConfig
어노테이션은 위의 2개의 애노테이션을 합친 애노테이션이다. 그래서 2줄을 1줄로 바꿀 수 있는 좋은(?) 애노테이션이다. 한번 해보자.
@SpringJUnitConfig(Application.class)
class AnnotationHelloServiceTests {
private final HelloService helloService;
@Autowired
AnnotationHelloServiceTests(HelloService helloService) {
this.helloService = helloService;
}
@Test
void parametersHello(@Autowired HelloService helloService) {
assertEquals(helloService.hello(), "hello world");
}
@Test
void constructorHello(@Autowired HelloService helloService) {
assertEquals(this.helloService.hello(), "hello world");
}
}
위와 같이 작성해도 기존과 동일한 코드로 동작한다.
@SpringJUnitConfig
애노테이션 말고도 web을 지원해주는
@SpringJUnitWebConfig
애노테이션도 존재한다. 이것은 한번씩 해보도록 하자. 그렇다고 크게 어려운건 없고
@WebAppConfiguration
애노테이션 한개가 추가 됐을 뿐이다.
눈치빠른 사람들은 눈치챘겠지만 junit5 또한 메타 애노테이션을 지원한다. Spring과 비슷하게 가고 있는 듯하다. 테스트를 위해 좀 더 코드를 작성해보자.
@Configuration
public class Application {
@Bean
HelloService helloService() {
return () -> "hello world";
}
@Profile("default")
static class TestOrder {
@Bean
OrderService orderService() {
return name -> "hello " + name;
}
}
@Profile("dev")
static class DevOrder {
@Bean
OrderService devOrderService() {
return name -> "hello dev " + name;
}
}
}
아까 위의 코드에서 클래스 2개가 추가 되었다. 하나의 클래스는 Profile이
default
일때 또 다른 한개의 클래스는
dev
일 때 동작한다고 가정해보자. 그리고나서 아래와 같은 메타 어노테이션을 만들어보자.
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@SpringJUnitConfig(Application.class)
@ActiveProfiles("dev")
public @interface DevTestConfig {
}
여기에는
@SpringJUnitConfig
와
@ActiveProfiles
애노테이션 두개가 메타 어노테이션으로 정의 되어있다. 이 어노테이션은 dev의 Profile만 적용되는 애노테이션이다. 한번 그렇게 되나 테스트를 해보자.
@DevTestConfig
class DevHelloServiceTest {
private final OrderService orderService;
@Autowired
DevHelloServiceTest(OrderService orderService) {
this.orderService = orderService;
}
@Test
void hello() {
assertEquals(orderService.ordered("wonwoo"), "hello dev wonwoo");
}
}
위에서 보다 시피
dev
쪽의 bean은
"hello dev " + name
문자열로
dev
라는 문자열이 포함되어 있다. 만약
dev
프로파일이 적용이 되었다면 위의 테스트 코드는 통과해야만 한다. 만약 그렇지 않고 기본 프로파일이 적용된다면 이 테스트는 실패로 돌아간다.
한번 테스트를 돌려보면 이상없이 테스트 코드가 잘 동작하는 것을 볼 수 있다.
우리는 이렇게 junut5로 spring를 테스트하는 코드를 작성해봤다. 그렇게 많이 어려운 내용은 아닌 듯 싶다. 아직 당분간은 회사에서 사용할 일은 없기에 개인적으로만 사용해야겠다.
위의 해당 소스는
여기에 있으니 한번씩 돌려보도록 하자.