💬

KoinTestでランタイム時の依存性によるクラッシュの不安に備える

2022/02/09に公開

といいつつ筆者は脱Koin化しようとしています。だって依存性注入ちゃんとできているか自分でテスト書くより型検査でなんとかしてくれたほうが嬉しいじゃん・・・

Koin使ってて怖いことといえば、設定をミスっててもビルドでは気づけず、ランタイムでクラッシュを踏むまで気づかない可能性があるということ。
ここでどういうケースでクラッシュするか考えると

  • 循環参照
  • 未定義オブジェクト
    になります。

これらに対して、Koinが用意しているTestにより気づくことができます。

checkModules

checkModulesはKoin DSLで定義された範囲内での依存性をチェックします。

class CheckModulesTest : KoinTest {

    @Test
    fun verifyKoinApp() {
        koinApplication {
            modules(module1,module2)
            checkModules()
        }
    }
}

未定義オブジェクト

module {
   single {
        B(a = get<A>())
    }
}

class A
data class B(val a: A)

Koinで定義されていないオブジェクトを get() しようとしています。この場合以下のような例外がでます。

java.lang.RuntimeException: org.koin.core.error.InstanceCreationException: Could not create instance for [Single:'B']

Caused by: org.koin.core.error.InstanceCreationException: Could not create instance for [Single:'B']

Caused by: org.koin.core.error.NoBeanDefFoundException: No definition found for class:'A'. Check your definitions!

循環参照

module {
   single {
        C(d = get<D>())
    }
   single {
        D(c = get<C>())
    }
}

data class C(val d: D)
data class D(val c: C)

checkModules()を実行すると、循環参照を検知してくれるわけではありません。ですがCの生成のためにDの生成を呼び出し、そのためにCの生成を呼び出し・・・と無限に呼び出しを繰り返し最終的にstackoverflowを起こしてテストがコケます。

取得テスト

checkmodulesはKoin DSLで定義された範囲内部での依存性解決を行うので、逆に言うとその外のことは確認できません。
例えば by inject() したクラスがKoinDSLで定義されていなくてもcheckModulesは通ります。

そこでテスト内でKoinから取得することで、実際にそのオブジェクトが宣言されているかを確認できいます。

    @Test
    fun verifyKoinApp() {
        
        koinApplication {
            modules(module1,module2)
            checkModules {
	      assertThat(get<A>()).isNotNull()
	    }
        }
    }

Discussion