Loading...
Spring Framework Reference Documentation 7.0.2의 Dependency Injection of Test Fixtures의 한국어 번역본입니다.
아래의 경우에 피드백에서 신고해주신다면 반영하겠습니다.
감사합니다 :)
기본으로 설정되는 DependencyInjectionTestExecutionListener를 사용하면, @ContextConfiguration 또는 관련 어노테이션으로 구성한 애플리케이션 컨텍스트의 빈들로부터 테스트 인스턴스의 의존성이 주입됩니다. 어떤 어노테이션을 선택하는지와 그것을 세터 메서드나 필드에 배치하는지에 따라 세터 주입, 필드 주입 또는 둘 다 사용할 수 있습니다.
JUnit Jupiter를 사용 중이라면 선택적으로 생성자 주입도 사용할 수 있습니다(SpringExtension을 사용한 Dependency Injection 참고). Spring의 어노테이션 기반 주입 지원과의 일관성을 위해 필드와 세터 주입에 Spring의 @Autowired 어노테이션이나 JSR-330의 @Inject 어노테이션을 사용할 수도 있습니다.
JUnit Jupiter 이외의 테스트 프레임워크의 경우, TestContext 프레임워크는 테스트 클래스의 인스턴스화에 참여하지 않습니다. 따라서 생성자에 대해
@Autowired나@Inject를 사용하는 것은 테스트 클래스에 아무 효과가 없습니다.
필드 주입은 프로덕션 코드에서 권장되지 않지만, 테스트 코드에서는 필드 주입이 실제로 꽤 자연스럽습니다. 차이가 나는 근거는 테스트 클래스를 직접 인스턴스화하는 일이 결코 없다는 점입니다. 결과적으로 테스트 클래스에서
public생성자나 세터 메서드를 호출할 수 있을 필요가 없습니다.
@Autowired는 autowiring by type을 수행하는 데 사용되므로 동일한 타입의 빈 정의가 여러 개 있는 경우 해당 빈들에 대해서는 이 방식을 신뢰할 수 없습니다. 그런 경우 @Qualifier와 함께 @Autowired를 사용할 수 있습니다. 또한 @Inject를 @Named와 함께 사용하는 것을 선택할 수도 있습니다.
또는 테스트 클래스가 자신의 ApplicationContext에 접근할 수 있다면, 예를 들어 applicationContext.getBean("titleRepository", TitleRepository.class) 호출을 사용하여 명시적인 조회를 수행할 수 있습니다.
테스트 인스턴스에 의존성 주입이 적용되기를 원하지 않는다면 필드나 세터 메서드에 @Autowired나 @Inject를 어노테이션으로 지정하지 마십시오. 또는 @TestExecutionListeners로 클래스를 명시적으로 구성하고 리스너 목록에서 DependencyInjectionTestExecutionListener.class를 생략하여 의존성 주입 자체를 비활성화할 수 있습니다.
Goals 섹션에 개략적으로 설명된 것처럼 HibernateTitleRepository 클래스를 테스트하는 시나리오를 생각해 보십시오. 다음 두 코드 리스트는 필드와 세터 메서드에서 @Autowired를 사용하는 예를 보여 줍니다.
애플리케이션 컨텍스트 설정은 모든 샘플 코드 리스트 뒤에 제시됩니다.
다음 코드 리스트에서의 의존성 주입 동작은 JUnit Jupiter에만 특정된 것이 아닙니다. 동일한 DI 기법은 지원되는 어떤 테스트 프레임워크와도 함께 사용할 수 있습니다. 다음 예제에서는
assertNotNull()과 같은 정적 단언 메서드를 호출하지만, 호출 앞에Assertions를 붙이지 않습니다. 이런 경우, 예제에 표시되지 않은import static선언을 통해 해당 메서드가 적절히 import되었다고 가정하십시오.
첫 번째 코드 리스트는 필드 주입을 위해 @Autowired를 사용하는 JUnit Jupiter 기반 테스트 클래스 구현을 보여 줍니다:
1@ExtendWith(SpringExtension.class) 2// specifies the Spring configuration to load for this test fixture 3@ContextConfiguration("repository-config.xml") 4class HibernateTitleRepositoryTests { 5 6 // this instance will be dependency injected by type 7 @Autowired 8 HibernateTitleRepository titleRepository; 9 10 @Test 11 void findById() { 12 Title title = titleRepository.findById(new Long(10)); 13 assertNotNull(title); 14 } 15}
1@ExtendWith(SpringExtension::class) 2// specifies the Spring configuration to load for this test fixture 3@ContextConfiguration("repository-config.xml") 4class HibernateTitleRepositoryTests { 5 6 // this instance will be dependency injected by type 7 @Autowired 8 lateinit var titleRepository: HibernateTitleRepository 9 10 @Test 11 fun findById() { 12 val title = titleRepository.findById(10) 13 assertNotNull(title) 14 } 15}
또는 다음과 같이 클래스를 구성하여 세터 주입에 @Autowired를 사용할 수 있습니다:
1@ExtendWith(SpringExtension.class) 2// specifies the Spring configuration to load for this test fixture 3@ContextConfiguration("repository-config.xml") 4class HibernateTitleRepositoryTests { 5 6 // this instance will be dependency injected by type 7 HibernateTitleRepository titleRepository; 8 9 @Autowired 10 void setTitleRepository(HibernateTitleRepository titleRepository) { 11 this.titleRepository = titleRepository; 12 } 13 14 @Test 15 void findById() { 16 Title title = titleRepository.findById(new Long(10)); 17 assertNotNull(title); 18 } 19}
1@ExtendWith(SpringExtension::class) 2// specifies the Spring configuration to load for this test fixture 3@ContextConfiguration("repository-config.xml") 4class HibernateTitleRepositoryTests { 5 6 // this instance will be dependency injected by type 7 lateinit var titleRepository: HibernateTitleRepository 8 9 @Autowired 10 fun setTitleRepository(titleRepository: HibernateTitleRepository) { 11 this.titleRepository = titleRepository 12 } 13 14 @Test 15 fun findById() { 16 val title = titleRepository.findById(10) 17 assertNotNull(title) 18 } 19}
앞의 코드 리스트들은 @ContextConfiguration 어노테이션에 의해 참조되는 동일한 XML 컨텍스트 파일(즉, repository-config.xml)을 사용합니다. 다음은 이 설정을 보여 줍니다:
1<?xml version="1.0" encoding="UTF-8"?> 2<beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 https://www.springframework.org/schema/beans/spring-beans.xsd"> 6 7 <!-- this bean will be injected into the HibernateTitleRepositoryTests class --> 8 <bean id="titleRepository" class="com.foo.repository.hibernate.HibernateTitleRepository"> 9 <property name="sessionFactory" ref="sessionFactory"/> 10 </bean> 11 12 <bean id="sessionFactory" class="org.springframework.orm.jpa.hibernate.LocalSessionFactoryBean"> 13 <!-- configuration elided for brevity --> 14 </bean> 15 16</beans>
Spring이 제공하는 테스트 베이스 클래스를 상속하는데, 그 베이스 클래스가 우연히 자신의 세터 메서드 중 하나에
@Autowired를 사용하고 있고, 애플리케이션 컨텍스트에 해당 타입의 빈(예: 여러 개의DataSource빈)이 여러 개 정의되어 있을 수 있습니다. 이런 경우, 세터 메서드를 오버라이드하고@Qualifier어노테이션을 사용하여 다음과 같이 특정 타깃 빈을 지정할 수 있습니다(단, 슈퍼클래스의 오버라이드된 메서드로 위임하는 것도 잊지 마십시오):1// ... 2 @Autowired 3 @Override 4 public void setDataSource(@Qualifier("myDataSource") DataSource dataSource) { 5 super.setDataSource(dataSource); 6 } 7// ...1// ... 2 @Autowired 3 override fun setDataSource(@Qualifier("myDataSource") dataSource: DataSource) { 4 super.setDataSource(dataSource) 5 } 6// ...지정된 qualifier 값은 주입할 특정
DataSource빈을 나타내며, 타입 일치 집합을 특정 빈으로 좁혀 줍니다. 이 값은 해당<bean>정의 내의<qualifier>선언과 매칭됩니다. 빈 이름은 폴백 qualifier 값으로 사용되므로, (앞에서 보인 것처럼myDataSource가 빈id라고 가정하면) 이름으로도 특정 빈을 가리킬 수 있습니다.
Context Hierarchies
Bean Overriding in Tests