テストでのインジェクション
KoinTest でテストを KoinComponent にする
警告: これは Android のインストゥルメンテッドテスト(Instrumented tests)には適用されません。Android でのインストゥルメンテッドテストについては、Android Instrumented Testing を参照してください。
クラスに KoinTest を付与することで、そのクラスは KoinComponent になり、以下の機能が利用可能になります:
by inject()&get()- Koin からインスタンスを取得するための関数verify()- モジュール設定の検証を支援declareMock&declare- 現在のコンテキストでモックや新しい定義を宣言する
class ComponentA
class ComponentB(val a: ComponentA)
class MyTest : KoinTest {
// プロパティを Lazy インジェクトする
val componentB : ComponentB by inject()
@Test
fun `should inject my components`() {
startKoin {
modules(
module {
single { ComponentA() }
single { ComponentB(get()) }
})
}
// インスタンスを直接リクエストする
val componentA = get<ComponentA>()
assertNotNull(a)
assertEquals(componentA, componentB.a)
}NOTE
アプリを部分的に構築するために、Koin モジュールの設定をオーバーロードすることをためらわないでください。
JUnit ルール
テスト用の Koin コンテキストを作成する
以下のルールを使用することで、各テストに対して Koin コンテキストを簡単に作成・保持できます:
@get:Rule
val koinTestRule = KoinTestRule.create {
// ここに KoinApplication インスタンスを記述
modules(myModule)
}モックプロバイダーの指定
declareMock API を使用するには、Koin にモックインスタンスの構築方法を伝えるルールを指定する必要があります。これにより、ニーズに合った適切なモッキングフレームワークを選択できます。
Mockito を使用してモックを作成する場合:
@get:Rule
val mockProvider = MockProviderRule.create { clazz ->
// ここにモックの構築方法を記述
Mockito.mock(clazz.java)
}MockK を使用してモックを作成する場合:
@get:Rule
val mockProvider = MockProviderRule.create { clazz ->
// ここにモックの構築方法を記述
mockkClass(clazz)
}!> koin-test プロジェクトは、現在 Mockito に依存していません。
標準機能でのモッキング
モックが必要になるたびに新しいモジュールを作成する代わりに、declareMock を使用してその場でモックを宣言できます:
class ComponentA
class ComponentB(val a: ComponentA)
class MyTest : KoinTest {
@get:Rule
val koinTestRule = KoinTestRule.create {
modules(
module {
single { ComponentA() }
single { ComponentB(get()) }
})
}
@get:Rule
val mockProvider = MockProviderRule.create { clazz ->
Mockito.mock(clazz.java)
}
@Test
fun `should inject my components`() {
}
// 現在の定義をモックに置き換える
val mock = declareMock<ComponentA>()
// モックを取得する(上記の変数と同じ)
assertNotNull(get<ComponentA>())
// モック化された ComponentA で構築される
assertNotNull(get<ComponentB>())
}NOTE
declareMock では、single か factory か、またモジュールパスに配置するかどうかを指定できます。
コンポーネントの動的な宣言
モックでは不十分で、かつそのためのモジュールをわざわざ作成したくない場合は、declare を使用できます:
@Test
fun `successful declare an expression mock`() {
startKoin { }
declare {
factory { ComponentA("Test Params") }
}
Assert.assertNotEquals(get<ComponentA>(), get<ComponentA>())
}Koin モジュールのチェック
Koin は、Koin モジュールが正しいかどうかをテストする方法を提供しています:verify() - 定義ツリーを走査し、各定義がバインドされているかチェックします。
@Test
fun checkKoinModules() {
myModule.verify()
}INFO
checkModules() API は非推奨(Deprecated)になりました。代わりに verify() を使用してください。詳細は Module Verification を参照してください。
両方の検証 API は、Koin Compiler Plugin のネイティブなコンパイル時の安全性(compile-time safety)に置き換えられる予定です。
テストでの Koin の開始と停止
テストごとに Koin インスタンスを停止する(テスト内で startKoin を使用する場合)ように注意してください。そうでない場合は、ローカルの Koin インスタンスには koinApplication を使用するか、現在のグローバルインスタンスを停止するために stopKoin() を使用してください。
JUnit 5 でのテスト
JUnit 5 のサポートでは、Koin コンテキストの開始と停止を処理する Extensions が提供されています。つまり、この extension を使用している場合は AutoCloseKoinTest を使用する必要はありません。
依存関係
JUnit 5 でテストするには、koin-test-junit5 の依存関係を使用する必要があります。
テストの記述
KoinTestExtension を登録し、モジュール設定を提供する必要があります。これが完了したら、テストでコンポーネントを取得(get)またはインジェクト(inject)できます。@RegisterExtension と併せて @JvmField を使用することを忘れないでください。
class ExtensionTests: KoinTest {
private val componentB by inject<Simple.ComponentB>()
@JvmField
@RegisterExtension
val koinTestExtension = KoinTestExtension.create {
modules(
module {
single { Simple.ComponentA() }
single { Simple.ComponentB(get()) }
})
}
@Test
fun contextIsCreatedForTheTest() {
Assertions.assertNotNull(get<Simple.ComponentA>())
Assertions.assertNotNull(componentB)
}
}JUnit 5 でのモッキング
これは、@RegisterExtension を使用する必要がある点を除けば、JUnit 4 と同じように動作します。
class MockExtensionTests: KoinTest {
val mock: Simple.UUIDComponent by inject()
@JvmField
@RegisterExtension
val koinTestExtension = KoinTestExtension.create {
modules(
module {
single { Simple.UUIDComponent() }
})
}
@JvmField
@RegisterExtension
val mockProvider = MockProviderExtension.create { clazz ->
Mockito.mock(clazz.java)
}
@Test
fun mockProviderTest() {
val uuidValue = "UUID"
declareMock<Simple.UUIDComponent> {
BDDMockito.given(getUUID()).will { uuidValue }
}
Assertions.assertEquals(uuidValue, mock.getUUID())
}
}作成された Koin インスタンスの取得
作成された Koin コンテキストを関数のパラメータとして取得することもできます。これは、テスト関数に関数パラメータを追加することで実現できます。
class ExtensionTests: KoinTest {
@RegisterExtension
@JvmField
val koinTestExtension = KoinTestExtension.create {
modules(
module {
single { Simple.ComponentA() }
})
}
@Test
fun contextIsCreatedForTheTest(koin: Koin) {
// get<SimpleComponentA>() == koin.get<Simple.ComponentA>()
Assertions.assertNotNull(koin.get<Simple.ComponentA>())
}
}