ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Kotlin 에서 Spring 으로 테스트할 때 주의사항
    Spring 2023. 2. 14. 20:19

    문제 상황

    • kotlin 에서 JUnit 을 사용하여 테스트를 구성했지만 org.junit.jupiter.api.extension.ParameterResolutionException: No ParameterResolver registered for parameter 오류가 발생했습니다.
    • @SpringBootTest
      class MemberRepositoryTest(
         val memberRepository: MemberRepository,
      ) {
         @Test
         @DisplayName("멤버 삭제")
         fun deleteMember() {    
             val member = memberRepository.save(MemberFactory.of("test"))  
             memberRepository.delete(member)
        }
      }

    해결 방법

    우선 junit.jupiter 에서 궁금한 점이 생겼습니다.

    Junit 5 의 경우 크게 3가지 부분으로 이루어져 있습니다.

    • Jupiter
      • JUnit platform 을 구현한 구현체로, JUnit 5의 구현체입니다.
    • Vintage
      • JUnit platform 을 구현한 구현체로, JUnit3, 4 의 구현체 입니다.
    • JUnit Platform
      • 실행할 수 있는 엔진을 포함하고 여러 도구에 일관성있는 API 를 제공합니다.

    그다음 ParameterResolver 의 역할이 궁금했습니다.

    생성자 매개변수의 경우 main 패키지에 있는 코드들은 Spring IoC 컨테이너가 이를 해결합니다. 하지만 test 패키지에서는 생성자 매개변수 관리를 Jupiter 가 담당하게 됩니다. 그래서 @Autowired 를 명시적으로 선언해주어야 Jupiter 가 Spring Contrainer 에게 빈 주입을 요청 할 수 있습니다.

    테스트 프레임워크에서 프레임워크의 주체는 Jupiter 이기 때문에 생성자 주입이라 한들 @Autowired 애노테이션이 명시되지 않은 객체는 의존성 주입을 받을 수 없게 됩니다.

    Jupiter 는 생성자 매개변수를 처리할 ParameterResolver 를 찾지만 이를 다룰 수 있는 ParameterResolver 를 찾을 수 없고, 예외를 던지게 됩니다. 따라서 @Autowired 를 사용해 Jupiter가 Spring Container 에게 빈 주입을 요청하도록 @Autowired 애노테이션을 추가하면 해결됩니다.

    @SpringBootTest
    class MemberRepositoryTest @Autowired constructor(
        val memberRepository: MemberRepository,
    ) {
        @Test
        @DisplayName("멤버 삭제")
        fun deleteMember() {    
            val member = memberRepository.save(MemberFactory.of("test"))   
            memberRepository.delete(member)
        }
    }

    향상된 방법

    JUnit5 부터는 생성자를 통한 의존관계 주입이 가능해졌습니다.

    Spring 에서 제공하는 @TestConstructor 애노테이션을 사용하면 됩니다. 이를 사용하면 테스트 클래스 생성자에 들어있는 필드들에 의존관계를 주입해 줄 수 있습니다. 주입해줄 수 있는 방법은 크게 2가지 방법이 있습니다.

    1. ALL
      • 테스트 생성자의 모든 파라미터는 자동 주입이 됩니다.(생성자의 모든 파라미터에 @Autowired 가 붙어있다고 생각하면 편합니다.)
    2. ANNOTATED
      • @Autowired, @Qualifer, @Value 로 어노테이션이 붙어져 있는 생성자 필드에 대해 각각이 자동 주입됩니다.
    @SpringBootTest
    @TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL)
    class MemberRepositoryTest (
        val memberRepository: MemberRepository,
    ) {
        @Test
        @DisplayName("멤버 삭제")
        fun deleteMember() {    
            val member = memberRepository.save(MemberFactory.of("test"))   
            memberRepository.delete(member)
        }
    }

    'Spring' 카테고리의 다른 글

    Spring delete 메소드 주의사항  (0) 2023.02.14
    Spring Bean  (0) 2022.07.25
    Spring에 비해 SpringBoot 가 가지는 특징  (0) 2022.07.03
    Filter 와 Interceptor 의 차이  (0) 2022.06.26
    @Transaction(readOnly = True)  (0) 2022.05.08

    댓글