🔪

Dagger Hilt でスマートにモックに差し替える

2024/09/10に公開

よくやりたくなるのが、モック用の product flavor の時のみに、通信をモックした UseCase や Repository を利用したいというもの。且つ、モック用のクラスはプロダクションのコードに含めたくない。

flavor 毎に Dagger のモジュールを作って当該クラスのインスタンスを @Provides で定義しつつ、モック用の flavor だけモックのレスポンスを返すようにすればよいが、一つのクラスをモックするのに全 flavor のモジュールに @Provides の定義を記載してメンテしていかないとといけないので煩雑である。

その解決として、次のような inline 関数をモック用の flavor のソースツリーに配置する。

kotlin
inline fun <reified T> replaceMock(block: () -> T): T {
    return when (T::class) {
        // モックしたいクラスの分だけこれを並べる。inteface をきっておく必要はある
        HogeUseCase::class -> object : HogeUseCase {
            override suspend fun invoke(): Hoge {
                // モックのレスポンスをここに書く
                // ...
            }
        } as T

        else -> block.invoke()
    }
}

モック用以外の falvor のソースツリーには下記のような「何もしない」コードを配置しておく。

kotlin
inline fun <reified T> replaceMock(block: () -> T): T {
    return block.invoke()
}

main のソースツリー上の Dagger の定義は次のとおり。

kotlin
@Provides
fun provideHogeUseCase(
    hogeRepository: hogeRepository,
): HogeUseCase = replaceMock<HogeUseCase> {
    // モックしない場合のインスタンス
    HogeUseCaseImpl(hogeRepository)
}

定義を間違えると as T のキャストのところで例外が発生するが、これはコンパイル時に分かるので実用上は問題ない。

株式会社ゆめみ

Discussion