티스토리 뷰
회사 동료 분이 스프링 테스트를 하며 오류가 난다고 도움을 요청하셨는데, 살펴보니 크게 두 가지 이슈가 있었고 주요 문제는 @SpringBootApplication
클래스를 포함하지 않는 프로젝트라 @SpringBootTest
가 수행이 되지 상황이었다.
이와 관련해서 자료를 찾다보니 마음에 드는 답변은 스프링 테스트 전반에 걸친 내용을 작성한 글 중 일부로 있었고, 간단한 해결 방법들은 지금과 같은 상황에서 좋은 해결책은 아니었다.
그래서 샘플 코드와 함께 내 나름대로의 해결 방식을 정리를 해두려고 한다.
1. 프로젝트 준비
에러 재현을 위해 구성한 프로젝트는 다음과 같다. 특이 사항이라면, 어플리케이션을 기동하기 위한 엔트리 포인트가 없다는 것이고 다음으로 SampleService
가 의존하고 있는 SampleRepository
구현체가 해당 프로젝트에는 없다는 점이다.
어플리케이션 아키텍처는 아래 그림과 같이 DIP
를 적용해, 어플리케이션 레이어의 서비스가 레포지토리 빈을(저수준 모듈
) 직접 의존하는 것이 아니라 도메인 레이어의 인터페이스를(고수준 모듈
) 의존하도록 구성하였다.
2. 테스트 에러 재현
테스트 코드를 아래와 같이 작성했을 때 문제가 되는 부분은 먼저 서비스에서 의존하고 있는 리포지토리 객체가 없다는 점이고, 다음으로는 @SpringBootApplication
어노테이션을 사용하는 클래스가 없으므로 @SpringBootTest
가 사용하는 @SpringBootConfiguration
을 찾을 수 없다는 점이다.
@SpringBootTest
class BootApplicationTests {
@Autowired
SampleService sampleService;
@Test
void di_test() {
assertThat(sampleService.findContentsById(1L))
.isEqualTo("hello, 1");
}
}
에러 메세지
Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your test
java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your test
3. 해결
@SpringBootConfiguration
을 찾을 수 없어서 발생하는 문제는 @SpringBootApplication
어노테이션을 사용하는 클래스가 있을 경우 발생하지 않게 할 수 있고, 실제로 몇몇 블로그나 포스팅에서는 @SpringBootApplication
을 생성해서 사용하라는 답변도 있었다.
참고: @SpringBootApplication
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration 🔥
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
...
}
하지만, 다른 어플리케이션의 의존성으로 사용하기 위해 만든 프로젝트에서 어플리케이션의 엔트리포인트가 되는 어노테이션을 사용할 필요가 없으므로 다른 방식으로 해결하려고 한다.
테스트 코드
에러 메세지에 친절히 나와있는 것처럼 @SpringBootTest
어노테이션 내에 classes
속성을 활용해, @Configuration
클래스를 지정한다. 참고로, classes
속성은 지정한 클래스를 빈으로 생성한다.
@SpringBootTest(classes = SampleRepositoryConfiguration.class)
class BootApplicationTests {
@Autowired
SampleService sampleService;
@Test
void di_test() {
assertThat(sampleService.findContentsById(1L))
.isEqualTo("hello, 1");
}
}
configuration
@SpringBootTest
의 classes
속성으로 지정한 클래스에서는 서비스에서 의존하고 있는 리포지토리의 구현체를 만들고, @ComponentScan
어노테이션을 활용해 테스트에서 필요한 빈들을 생성하도록 한다.
@Configuration
@ComponentScan(basePackages = "com.example")
public class SampleRepositoryConfiguration {
@Bean
public SampleRepository sampleRepository() {
return id -> "hello, " + id;
}
}
테스트 결과
테스트를 위한 리포지토리 구현체를 만들어 서비스 빈을 정상적으로 생성하여, 테스트가 통과했다는 것을 확인할 수 있다.
샘플 코드 🤓
'스프링' 카테고리의 다른 글
[Spring] 어플리케이션 종료 시 들어온 요청은 처리하고 마치기(graceful shutdown) (0) | 2023.11.05 |
---|---|
[Spring] 어플리케이션을 종료할 때 특정 작업 수행하기(feat. ApplicationListener) (0) | 2023.11.05 |
[Spring] 초기 데이터 로딩(data.sql, schema.sql) (0) | 2023.06.02 |
[Spring] 주기적인 작업 구현하기(feat. Scheduling Tasks) (0) | 2023.04.01 |
[Spring Integration] 소개 및 튜토리얼 (0) | 2023.03.18 |