작성
·
441
·
수정됨
0
package hello.jdbc.service;
@SpringBootTest
class MemberServiceV3_3Test { //테스트에서는 Public 없어도 됨
@Autowired
MemberRepositoryV3 memberRepository;
@Autowired
MemberServiceV3_3 memberService;
@TestConfiguration
static class TestConfig {
@Bean
DataSource dataSource() {
return new DriverManagerDataSource(URL, USERNAME, PASSWORD);
}
@Bean
PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
@Bean
MemberRepositoryV3 memberRepositoryV3() {
return new MemberRepositoryV3(dataSource());
}
@Bean
MemberServiceV3_3 memberServiceV3_3() {
return new MemberServiceV3_3(memberRepositoryV3());
}
}
여기서 @SpringBootTest를 사용하면 @SpringBootApplication 안에 있는 @ComponentScan을 사용한다고 알고 있습니다.
그리고 test의 package 위치가 hello.jdbc.service이므로hello.jdbc.service를 포함한 그 하위 패키지는 컴포넌트 스캔의 대상이 됩니다.
(hello.jdbc.service 에는 MemberServiceV1 ~ V3_3 이 있습니다)
(1) 여기까지 맞게 생각한건지 궁금합니다.
(2) 컴포넌트 스캔의 대상인 class인 MemberServiceV3_3Test를 스프링 컨테이너에 넣고
@Autowired MemberServiceV3_3 memberService;
를 하면 MemberServiceV3_3 타입의 빈을 조회해야하는데 MemberServiceV3_3클래스에는 @Configuration나 @Component가 없습니다.
서비스뿐만 아니라 MemberRepositoryV0 ~ V3 클래스도 전부 다 없습니다.
근데 어떻게 memberRepository,memberService 필드에 의존관계주입을 줄 수있는건가요?
등록된 MemberRepositoryV3타입이나 MemberServiceV3_3타입의 빈이 없는데??
(3)
@SpringBootTest가 있으면 해당 테스트 클래스는 특수하게 @Autowired를 허용해준다고 하는 데 이 허용안에는 MemberRepositoryV3 memberRepository;를 자동으로 빈으로 생성해주는 것도 포함되어 있는 건가요??
(4)
아니면 @TestConfiguration가 먼저 실행이되어 빈으로 생성이 되는 건가요??
강의 자료에서는
@TestConfiguration :
테스트 안에서 내부 설정 클래스를 만들어서 사용하면서 이 에노테이션을 붙이면,
스프링 부트가 자동으로 만들어주는 빈들에 추가로 필요한 스프링 빈들을 등록하고 테스트를 수행할 수 있다
라고 이미 자동으로 만들어주는 빈들에 추가로 만들어준다 라고 되있던데....
스프링 핵심원리 - 다양한 의존관계편을 보고 구글링을 해봐도 잘 모르겠네요...
질문이 많아 죄송합니다
답변주시면 정말 감사하겠습니다.
답변 1
1
안녕하세요, 코딩먹는하마 님. 공식 서포터즈 y2gcoder 입니다.
어떻게 보면 스프링 핵심 원리 - 기본편에 어울리는 질문인 것 같습니다 ㅎㅎ
하나씩 답변드려보겠습니다!
(1) @SpringBootTest를 쓰면 기본적으로는 @SpringBootApplication이 선언된 클래스를 찾아서 스프링 부트 애플리케이션을 실행합니다. 그러나 애플리케이션 클래스를 찾지 못했을 경우에는 테스트 클래스의 패키지를 시작으로 컴포넌트 스캔을 수행합니다. 이 때 basePackage 의 위치는 @SpringBootApplication 이 선언된 클래스 기준입니다! 그래서 예상하신 컴포넌트 스캔 대상이 다를 수는 있을 것 같습니다.
(2) 여기서 @Autowired가 가능한 이유는 @TestConfiguration에서 MemberServiceV3_3와 MemberRepositoryV3 빈을 명시적으로 등록했기 때문입니다. @Autowired 애노테이션은 스프링 컨테이너에서 해당 타입의 빈을 찾아서 의존성을 주입해주는 역할을 합니다. 이때 스프링 컨테이너는 @Component, @Service, @Repository, @Controller 등의 애노테이션을 포함한 클래스 뿐만 아니라 @Configuration에서 @Bean 애노테이션을 통해 등록된 빈들도 참조합니다. 따라서 MemberServiceV3_3와 MemberRepositoryV3 클래스에는 @Service, @Component 등의 애노테이션이 없지만, @TestConfiguration에서 @Bean을 통해 스프링 컨테이너에 등록되었으므로 @Autowired를 사용할 수 있는 것입니다.
(3) @SpringBootTest 애노테이션 자체는 MemberRepositoryV3를 빈으로 자동 생성해주는 기능은 없습니다. @SpringBootTest는 스프링 부트 애플리케이션을 테스트 환경에서 실행하기 위한 애노테이션입니다. 스프링 부트 애플리케이션을 실행하면 @ComponentScan이 동작하여 @Component, @Service, @Repository, @Controller 등의 애노테이션이 선언된 클래스를 빈으로 등록하고, @Autowired 애노테이션을 통해 의존성을 주입합니다. 하지만 MemberRepositoryV3 클래스에는 이러한 애노테이션이 선언되어 있지 않으므로 @Autowired를 통해 의존성을 주입받기 위해서는 @TestConfiguration에서 @Bean 애노테이션을 통해 스프링 컨테이너에 빈으로 등록해야 합니다.
(4) @TestConfiguration은 테스트 환경에서만 동작하는 @Configuration입니다. 이 애노테이션을 통해 @Bean 애노테이션을 사용하여 필요한 빈들을 추가적으로 등록할 수 있습니다. 테스트를 실행할 때 @SpringBootTest는 먼저 스프링 부트 애플리케이션을 실행하고, 그 후에 @TestConfiguration이 동작하여 빈들을 추가로 등록합니다. 따라서 테스트를 수행하는 동안에는 MemberServiceV3_3와 MemberRepositoryV3가 스프링 컨테이너에 빈으로 등록되어 있어 @Autowired를 통해 의존성을 주입받을 수 있습니다.
감사합니다.
추가적인 질문이 있습니다. 지금 테스트코드에서는 TestConfig를 통해 빈을 등록해가지고 memberRepository와 memberService 주입받고 테스트를 실행하면 해당 메서드가 @Transactional이 붙어있기에 프록시 객체까지 생성이 된건 잘 이해된것 같습니다.
그런데 테스트코드가 아닌 실제 애플리케이션을 돌리면 현재 따로 Component관련 어노테이션도 안붙였고 Config에 빈등록도 안했기때문에 실제로는 정상적으로 실행이 안되겠죠?
저 코드들은 테스트 패키지에서 작성했기 때문에 실제 애플리케이션 영역에 영향을 주지 않는 것이 맞습니다.
만약 애플리케이션 실행시 src/main/java 를 기준으로 각 빈들을 생성 후 의존성 주입을 하는 과정에서 의존성 주입을 해야 할 빈이 등록되지 않았다면 말씀하신 것처럼 에러를 뱉을 것입니다 :)
와우... 좋은 답변 정말 감사합니다. 많은 도움됐습니다 :)