テストフィクスチャの依存性注入

DependencyInjectionTestExecutionListener (デフォルトで設定)を使用すると、テストインスタンスの依存関係は、@ContextConfiguration または関連するアノテーションで設定したアプリケーションコンテキストの Bean から注入されます。選択するアノテーションと、setter メソッドまたはフィールドに配置するかどうかに応じて、setter インジェクション、フィールドインジェクション、その両方を使用できます。JUnit Jupiter を使用している場合は、オプションでコンストラクターインジェクションを使用することもできます(SpringExtension による依存性注入を参照)。Spring のアノテーションベースの注入サポートとの一貫性を保つため、Spring の @Autowired アノテーションまたは JSR-330 の @Inject アノテーションをフィールドおよび setter 注入に使用することもできます。

JUnit Jupiter 以外のテストフレームワークの場合、TestContext フレームワークはテストクラスのインスタンス化に参加しません。コンストラクターに @Autowired または @Inject を使用しても、テストクラスには効果がありません。
フィールドインジェクションは製品コードでは推奨されていませんが、実際にはテストコードではフィールドインジェクションは非常に自然です。違いの理由は、テストクラスを直接インスタンス化しないことです。テストクラスで public コンストラクターまたは setter メソッドを呼び出す必要はありません。

@Autowired は type によるオートワイヤーの実行に使用されるため、同じ型の Bean 定義が複数ある場合、それらの特定の Bean に対してこのアプローチに依存することはできません。その場合、@Autowired を @Qualifier と組み合わせて使用できます。@Inject を @Named と組み合わせて使用することも選択できます。あるいは、テストクラスが ApplicationContext にアクセスできる場合は、(たとえば) applicationContext.getBean("titleRepository", TitleRepository.class) の呼び出しを使用して明示的な検索を実行できます。

テストインスタンスに依存性注入を適用したくない場合は、フィールドまたは setter メソッドに @Autowired または @Inject でアノテーションを付けないでください。あるいは、@TestExecutionListeners を使用してクラスを明示的に構成し、リスナーのリストから DependencyInjectionTestExecutionListener.class を省略することにより、依存性注入を完全に無効にすることができます。

ゴールセクションで概説されているように、HibernateTitleRepository クラスをテストするシナリオを検討してください。次の 2 つのコードリストは、フィールドでの @Autowired および setter メソッドの使用箇所を示しています。アプリケーションコンテキスト構成は、すべてのサンプルコードリストの後に表示されます。

次のコードリストの依存性注入動作は、JUnit Jupiter に固有のものではありません。同じ DI テクニックは、サポートされているテストフレームワークと組み合わせて使用できます。

次の例では、assertNotNull() などの静的アサーションメソッドを呼び出しますが、呼び出しの先頭に Assertions を付けません。このような場合、この例には示されていない import static 宣言を介してメソッドが適切にインポートされたと想定します。

最初のコードリストは、フィールドインジェクションに @Autowired を使用するテストクラスの JUnit Jupiter ベースの実装を示しています。

  • Java

  • Kotlin

@ExtendWith(SpringExtension.class)
// specifies the Spring configuration to load for this test fixture
@ContextConfiguration("repository-config.xml")
class HibernateTitleRepositoryTests {

	// this instance will be dependency injected by type
	@Autowired
	HibernateTitleRepository titleRepository;

	@Test
	void findById() {
		Title title = titleRepository.findById(new Long(10));
		assertNotNull(title);
	}
}
@ExtendWith(SpringExtension::class)
// specifies the Spring configuration to load for this test fixture
@ContextConfiguration("repository-config.xml")
class HibernateTitleRepositoryTests {

	// this instance will be dependency injected by type
	@Autowired
	lateinit var titleRepository: HibernateTitleRepository

	@Test
	fun findById() {
		val title = titleRepository.findById(10)
		assertNotNull(title)
	}
}

または、次のように、setter インジェクションに @Autowired を使用するようにクラスを構成できます。

  • Java

  • Kotlin

@ExtendWith(SpringExtension.class)
// specifies the Spring configuration to load for this test fixture
@ContextConfiguration("repository-config.xml")
class HibernateTitleRepositoryTests {

	// this instance will be dependency injected by type
	HibernateTitleRepository titleRepository;

	@Autowired
	void setTitleRepository(HibernateTitleRepository titleRepository) {
		this.titleRepository = titleRepository;
	}

	@Test
	void findById() {
		Title title = titleRepository.findById(new Long(10));
		assertNotNull(title);
	}
}
@ExtendWith(SpringExtension::class)
// specifies the Spring configuration to load for this test fixture
@ContextConfiguration("repository-config.xml")
class HibernateTitleRepositoryTests {

	// this instance will be dependency injected by type
	lateinit var titleRepository: HibernateTitleRepository

	@Autowired
	fun setTitleRepository(titleRepository: HibernateTitleRepository) {
		this.titleRepository = titleRepository
	}

	@Test
	fun findById() {
		val title = titleRepository.findById(10)
		assertNotNull(title)
	}
}

上記のコードリストでは、@ContextConfiguration アノテーション(つまり repository-config.xml)によって参照される同じ XML コンテキストファイルを使用しています。以下にこの構成を示します。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
		https://www.springframework.org/schema/beans/spring-beans.xsd">

	<!-- this bean will be injected into the HibernateTitleRepositoryTests class -->
	<bean id="titleRepository" class="com.foo.repository.hibernate.HibernateTitleRepository">
		<property name="sessionFactory" ref="sessionFactory"/>
	</bean>

	<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
		<!-- configuration elided for brevity -->
	</bean>

</beans>

setter メソッドの 1 つで @Autowired を使用する Spring 提供のテストベースクラスから拡張している場合、アプリケーションコンテキストで定義された影響を受ける型の複数の Bean(たとえば、複数の DataSource Bean)があります。そのような場合、次のように、setter メソッドをオーバーライドし、@Qualifier アノテーションを使用して特定のターゲット Bean を示すことができます(ただし、スーパークラスのオーバーライドされたメソッドにも委譲するようにしてください)。

  • Java

  • Kotlin

// ...

	@Autowired
	@Override
	public void setDataSource(@Qualifier("myDataSource") DataSource dataSource) {
		super.setDataSource(dataSource);
	}

// ...
// ...

	@Autowired
	override fun setDataSource(@Qualifier("myDataSource") dataSource: DataSource) {
		super.setDataSource(dataSource)
	}

// ...

指定された修飾子の値は、注入する特定の DataSource Bean を示し、特定の Bean に一致する型のセットを絞り込みます。その値は、対応する <bean> 定義内の <qualifier> 宣言と照合されます。Bean 名はフォールバック修飾子の値として使用されるため、そこにある名前で特定の Bean を効果的に指すこともできます(前述のように、myDataSource が Bean id であると想定)。