[SpringBoot] IntelliJ와 Gradle이 테스트 구성을 처리하는 방식의 차이에서 발생한 오류
본문 바로가기
Spring/Spring Boot

[SpringBoot] IntelliJ와 Gradle이 테스트 구성을 처리하는 방식의 차이에서 발생한 오류

by IYK2h 2023. 6. 28.
728x90

문제 상황

기존 코드는 @SpringBootTest를 사용하였습니다. 테스트를 진행할 때 Intellij의 test를 실행하면 정상 작동되고 gradle clean test를 사용하면 빌드 오류가 났습니다.

즉, 테스트 & 개발할땐 전혀 문제가 없는데 빌드만 하면 저기가 실패합니다.

@SpringBootTest를 사용하면 @Configuration, @Component 등과 같은 주석을 사용하여 빈과 해당 종속성을 정의하여 Spring이 이러한 개체의 인스턴스화, 연결 및 수명 주기 관리를 처리할 수 있도록 합니다.

// 오류 코드
Could not detect default configuration classes for test class [com.ll.MOIZA.boundedContext.selectedTime.service.SelectedTimeServiceFindOverlappingTest]: SelectedTimeServiceFindOverlappingTest does not declare any static, non-private, non-final, nested classes annotated with @Configuration.
​
Found @SpringBootConfiguration com.ll.MOIZA.MoizaApplication for test class com.ll.MOIZA.boundedContext.selectedTime.service.SelectedTimeServiceFindOverlappingTest

하지만, 테스트 클래스에서 기본 구성 클래스를 감자할 수 없어서 나타나는 오류를 확인할 수 있습니다.

1차 원인

테스트 파일이 패키지 하위에 존재하지 않아서 @SpringBootApplication을 찾지 못하는 것이다.

1차 해결

// 기존 코드 @SpringBootTest 
@SpringBootTest(classes = MoizaApplication.class)

아직 끝나지 않은 문제 상황

404 NOT_FOUND "모임을 찾을 수 없습니다."
org.springframework.web.server.ResponseStatusException: 404 NOT_FOUND "모임을 찾을 수 없습니다."
  at app//com.ll.MOIZA.boundedContext.room.service.RoomService.lambda$getRoom$0(RoomService.java:101)
  at java.base@17.0.6/java.util.Optional.orElseThrow(Optional.java:403)
  at app//com.ll.MOIZA.boundedContext.room.service.RoomService.getRoom(RoomService.java:101)
  at java.base@17.0.6/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at java.base@17.0.6/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
  at java.base@17.0.6/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.base@17.0.6/java.lang.reflect.Method.invoke(Method.java:568)
  at app//org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343)

NotProd(테스트용 데이터)를 가져와야 하는데 가져오지 못하고 있습니다.

@Configuration
@Profile({"test", "dev"})
public class NotProd {
    @Bean
    CommandLineRunner commandLineRunner(
            RoomService roomService
    ) {
        return args -> {
​
            Room room = roomService.createRoom(
                    member1,
                    "테스트1",
                    "테스트룸임",
                    LocalDate.now().plusDays(5),
                    LocalDate.now().plusDays(7),
                    LocalTime.of(0, 0),
                    LocalTime.of(23, 0),
                    LocalTime.of(3, 0),
                    LocalDateTime.now().plusDays(2));
          ...
        }
    }
}
@SpringBootTest(classes = MoizaApplication.class)
@ActiveProfiles("test")
@Transactional
public class SelectedTimeServiceQueryTest {
  
    ...
  
    @BeforeEach
    void init() {
        member1 = memberService.findByName("user1");
        room = roomService.getRoom(1L);
    }
​
    @DisplayName("조회_선택_날짜")
    @Test
    void select_selected_time_by_day() {
        assertThat(selectedTimeService.findSelectedTimeByRoomAndDate(
                room, LocalDate.now().plusDays(6)).size()).isEqualTo(6);
    }
}

기존 코드에서 NotProd와 연결된 값이 명시적으로 지정되지 않았습니다.

 

이유는 NotProd와 SelectedTimeServiceQueryTest는 다른 패키지에 존재합니다. 그래서 application context에 자동으로 포함되지 않았습니다.

 

테스트 중 NotProd 구성 클래스를 포함하기위해 @Import를 사용합니다. @Import를 사용하면 이러한 테스트별 구성 클래스를 가져와서 테스트 중에 애플리케이션 컨텍스트에 포함되도록 할 수 있습니다.

@SpringBootTest(classes = MoizaApplication.class)
@ActiveProfiles("test")
@Transactional
@Import(NotProd.class)
public class SelectedTimeServiceQueryTest {
    
    ...
      
    @BeforeEach
    void init() {
        member1 = memberService.findByName("user1");
        room = roomService.getRoom(1L);
    }
  
    @DisplayName("조회_선택_날짜")
    @Test
    void select_selected_time_by_day() {
        assertThat(selectedTimeService.findSelectedTimeByRoomAndDate(
                room, LocalDate.now().plusDays(6)).size()).isEqualTo(6);
    }
}

이제 정상적으로 작동합니다. :)

이번 문제의 근본적인 원인 및 해결 방법

Intellij의 test를 실행하면 정상 작동되고 gradle clean test를 사용하면 빌드 오류가 왜 발생하는 이유는 IntelliJ와 Gradle이 클래스 경로 및 테스트 구성을 처리하는 방식이 다르기 때문입니다.

IntelliJ에는 테스트를 성공적으로 실행하는 데 필요한 클래스와 종속성이 자동으로 포함될 수 있는 자체 테스트 러너 및 클래스 경로 관리 기능이 있습니다. 패키지 스캔 또는 기타 구성 설정을 기반으로 NotProd 구성 클래스를 감지할 수 있습니다.

반면에 Gradle은 build.gradle과 같이 빌드 파일에 지정된 구성에 의존합니다. IntelliJ에 비해 테스트 실행 및 클래스 경로 관리에 대한 기본 설정이 다를 수 있습니다.

이 문제를 해결하고 IntelliJ와 Gradle 간에 일관된 동작을 보장하려면 앞서 언급한 대로 테스트 클래스에서 @Import를 사용하여 NotProd 구성 클래스를 명시적으로 지정하면 됩니다.

 

 

 

[SpringBoot] @SpringBootTest와 @Import

@SpringBootTest와 @Import Spring Boot에서 적절한 테스트 구성 접근 방식을 선택하는 것은 효과적이고 안정적인 테스트 환경을 만드는 데 중요합니다. 각 접근 방식의 목적, 용도, 특성 및 이점을 자세히

iyk2h.tistory.com

 

728x90

댓글