okuzawatsの日記

モバイルアプリケーション開発の沼💀

[Android] 単体テスト用の依存関係をHiltで解決する

書いている人

モバイルアプリケーションアーキテクトとして働いています。モバイルアプリケーションのアーキテクチャ、自動テスト、CI/CDに興味があります。


プロダクションとは異なる単体テストの依存関係をHiltで解決したい、ということってありますよね。僕はありました。

本記事では、単体テスト用の依存関係をHiltで解決する方法を示していきます。

単体テスト用の依存関係のセットアップ

Hiltのセットアップはできているものとして、さらに単体テスト用の依存関係を追加します。テスト用のHiltの依存関係の他、JUnit 4で使用するテストランナーとRobolectricを使います。

// use Hilt in tests
testImplementation "com.google.dagger:hilt-android-testing:2.46.1"
kaptTest "com.google.dagger:hilt-android-compiler:2.46.1"

// TestRunner
testImplementation "androidx.test.ext:junit-ktx:1.1.5"

// Robolectric
testImplementation "org.robolectric:robolectric:4.10.3"

テストクラスのセットアップ

テストクラスのセットアップにいくつかポイントがありますが、結論としては以下のように行いました。

import androidx.test.ext.junit.runners.AndroidJUnit4
import dagger.hilt.android.testing.HiltAndroidTest
import dagger.hilt.android.testing.HiltTestApplication
import org.junit.Test

import org.robolectric.annotation.Config
import javax.inject.Inject

@HiltAndroidTest
@Config(application = HiltTestApplication::class)
@RunWith(AndroidJUnit4::class)
class ExampleUnitTest {
  // 後述
}

ポイントは、以下です。

テストルールの設定

テストルールとしてHiltAndroidRuleを指定します。setupでHiltAndroidRule#injectを呼び出すことでInjectされます。

import dagger.hilt.android.testing.HiltAndroidRule

import org.junit.Before
import org.junit.Rule

@HiltAndroidTest
@Config(application = HiltTestApplication::class)
@RunWith(AndroidJUnit4::class)
class ExampleUnitTest {

  @get:Rule
  var hiltRule = HiltAndroidRule(this)

  @Inject lateinit var animal: Animal

  @Before
  fun setup() {
    hiltRule.inject()
  }
}

Moduleの差し替え

test 内にテスト用のモジュールを定義して、@TestInstallIn でそのモジュールを指定します。これを行うことで、単体テストの依存解決時に使用されるモジュールを差し替えることができます。またここでは、単体テストの依存解決時にMockkを利用したテストダブルを注入するように設定しています。

import dagger.Module
import dagger.Provides
import dagger.hilt.components.SingletonComponent
import dagger.hilt.testing.TestInstallIn
import io.mockk.every
import io.mockk.mockk

@Module
@TestInstallIn(
  components = [SingletonComponent::class],
  replaces = [AnimalModule::class]
)
class FakeAnimalModule {
  @Provides
  fun provideAnimal(): Animal {
    return mockk<Animal>().also {
      every { it.power() } returns 100
    }
  }
}

サンプルプロジェクトはGitHubに公開してあります。

テストダブルの活用

以下の記事では、例外のテストを行いたい場合にテストダブルを注入する方法を説明しています。

Related