ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • spring5 와 junit5
    카테고리 없음 2023. 4. 22. 14:40
    저번시간에 이어 오늘도 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를 테스트하는 코드를 작성해봤다. 그렇게 많이 어려운 내용은 아닌 듯 싶다. 아직 당분간은 회사에서 사용할 일은 없기에 개인적으로만 사용해야겠다. 위의 해당 소스는 여기에 있으니 한번씩 돌려보도록 하자.

    댓글

Designed by Tistory.