Test 에 사용할 클래스를 만들 때는 빈으로 주입 받거나, 객체로 직접 생성해야한다.
다음 방법들을 통해 어떻게 클래스의 인스턴스를 만들어서 사용할지 살펴보자
위와 같은 구조의 프로젝트일 때, Test 클래스에서 MemberFacade 를 생성하려면 MemberService 와 LogRepository 를 주입 받아야한다.
딱 봐도 비효율 적이다! 이런 보일러 플레이트는 지양하자
@RequiredArgsConstructor
@Slf4j
@Component // 빈으로 생성하도록 표시
public class MemberFacade {
private final MemberService memberService;
private final LogRepository logRepository;
...
}
// Test Class
...
@Autowired
MemberService memberService;
@Autowired
MemberRepository memberRepository;
@Autowired
LogRepository logRepository;
@Autowired
MemberFacade memberFacade;
...
이 방법에 문제는 없지만,
단위 테스트를 위해선 외부에 의존성을 끊어야하기 때문에 좋은 방법이 아니다.
그리고 생성된 Bean의 재정의가 불가능하다. (@Configuration 과 @ComponenetScan 차이!)
또한 스프링 컨테이너가 너무 많은 빈을 관리하게 되면, 매번 빈을 호출할 때 더 많은 빈을 순회해야 되므로 성능상 안 좋을 것이라 예상된다.
// Test Class
@Slf4j
@SpringBootTest
public class MyTest{
@Autowired
MemberService memberService;
@Autowired
MemberRepository memberRepository;
@Autowired
LogRepository logRepository;
@Autowired
MemberFacade memberFacade;
@TestConfiguration // 빈으로 생성하도록 설정 표시
public static class Config{
@Bean
public static MemberFacade makeMemberFacade(MemberService memberService, LogRepository logRepository){
return new MemberFacade(memberService, logRepository);
};
}
...
}
위 방법은 Test 할 시에만 빈을 생성해서 관리하기 때문에 기존 애플리케이션 성능에도 지장없이 테스트할 수 있다.
또한 @TestConfiguration 을 이용한다면, 외부와 연결도 끊은 mock service 를 사용할 수 있다.
⚠️주의
@Configuration 을 static 내부 클래스로 빈 생성 시 MemberService, LogRepository 빈을 찾을 수 없다는 오류가 발생한다.
이는 @TestConfiguration 은 @TestComponent를 정의했기 때문에 Spring Boot 의 comonent scaning 에서 제외되기 때문이다.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@TestComponent
public @interface TestConfiguration {
}
@Configuration 을 사용한다면 다음과 같이 외부로 클래스를 빼줘야한다
@Configuration
class Config{
@Bean
public MemberFacade makeMemberFacade(MemberService memberService, LogRepository logRepository){
return new MemberFacade(memberService, logRepository);
};
}
@Slf4j
@SpringBootTest
@Import(Config.class)
public class MyTest{
@Autowired
MemberService memberService;
@Autowired
MemberRepository memberRepository;
@Autowired
LogRepository logRepository;
@Autowired
MemberFacade memberFacade;
...
}