Hilt test kılavuzu

Hilt gibi bağımlılık ekleme çerçevelerini kullanmanın avantajlarından biri, kodunuzu test etmeyi kolaylaştırmasıdır.

Birim testleri

Oluşturucu yerleştirme kullanan bir sınıfı test ederken bu sınıfı örneklendirmek için Hilt kullanmanız gerekmediğinden birim testleri için Hilt gerekli değildir. Bunun yerine, yapıcıda ek açıklama yokmuş gibi sahte veya taklit bağımlılıkları ileterek sınıf yapıcısını doğrudan çağırabilirsiniz:

@ActivityScoped
class AnalyticsAdapter @Inject constructor(
  private val service: AnalyticsService
) { ... }

class AnalyticsAdapterTest {

  @Test
  fun `Happy path`() {
    // You don't need Hilt to create an instance of AnalyticsAdapter.
    // You can pass a fake or mock AnalyticsService.
    val adapter = AnalyticsAdapter(fakeAnalyticsService)
    assertEquals(...)
  }
}

Aynı durum, composable'larınızda hiltViewModel() çağrılarak elde edilen ViewModel sınıfları için de geçerlidir. Birim testlerinde ViewModel'i doğrudan sahte nesnelerle oluşturun. Durumun ViewModel'den composable'lara nasıl aktarıldığı hakkında bilgi edinmek için Durum ve Jetpack Compose ile Durumu nerede yukarı taşıyabilirsiniz? başlıklı makaleleri inceleyin.

Uçtan uca testler

Entegrasyon testleri için Hilt, bağımlılıkları üretim kodunuzda olduğu gibi ekler. Hilt ile test yapmak bakım gerektirmez çünkü Hilt her test için otomatik olarak yeni bir bileşen grubu oluşturur.

Test bağımlılıkları ekleme

Testlerinizde Hilt'i kullanmak için projenize hilt-android-testing bağımlılığını ekleyin:

dependencies {
    // For Robolectric tests.
    testImplementation("com.google.dagger:hilt-android-testing:2.57.1")
    kspTest("com.google.dagger:hilt-android-compiler:2.57.1")

    // For instrumented tests.
    androidTestImplementation("com.google.dagger:hilt-android-testing:2.57.1")
    kspAndroidTest("com.google.dagger:hilt-android-compiler:2.57.1")

    // Compose UI test rule.
    androidTestImplementation("androidx.compose.ui:ui-test-junit4")
    debugImplementation("androidx.compose.ui:ui-test-manifest")

}

Kullanıcı arayüzü testi kurulumu

Hilt kullanan tüm kullanıcı arayüzü testlerine @HiltAndroidTest ek açıklamasını eklemeniz gerekir. Bu ek açıklama, her test için Hilt bileşenlerini oluşturmaktan sorumludur.

Ayrıca, test sınıfına HiltAndroidRule eklemeniz gerekir. Bileşenlerin durumunu yönetir ve testinizde ekleme yapmak için kullanılır:

@HiltAndroidTest
class SettingsScreenTest {

    @get:Rule(order = 0)
    val hiltRule = HiltAndroidRule(this)

    @get:Rule(order = 1)
    val composeRule = createAndroidComposeRule<HiltTestActivity>()

    // Compose UI tests here.
}

Ardından, testinizin Hilt'in sizin için otomatik olarak oluşturduğu Application sınıfını bilmesi gerekir.

Hilt'in bağımlılıkları eklemesine izin vermek için androidTest kaynak grubunuzda HiltTestActivity adlı boş bir etkinlik oluşturmanız ve bu etkinliğe @AndroidEntryPoint ile ek açıklama eklemeniz gerekir. createAndroidComposeRule, daha sonra bu etkinliği, composable içeriğinizin ana makinesi olarak kullanır.

Test uygulaması

Hilt'i kullanan araçlı testleri, Hilt'i destekleyen bir Application nesnesinde yürütmeniz gerekir. Kitaplık, testlerde kullanılmak üzere HiltTestApplication sağlar. Testleriniz için farklı bir temel uygulama gerekiyorsa Testler için özel uygulama bölümüne bakın.

Test uygulamanızı enstrümantasyon testlerinizde veya Robolectric testlerinizde çalışacak şekilde ayarlamanız gerekir. Aşağıdaki talimatlar Hilt'e özel değildir. Testlerde çalıştırılacak özel bir uygulamanın nasıl belirtileceğine dair genel yönergelerdir.

Enstrümantasyon testlerinde test uygulamasını ayarlama

Hilt test uygulamasını enstrümantasyon testlerinde kullanmak için yeni bir test çalıştırıcı yapılandırmanız gerekir. Bu sayede Hilt, projenizdeki tüm enstrümantasyon testlerinde çalışır. Aşağıdaki adımları uygulayın:

  1. androidTest klasöründe AndroidJUnitRunner sınıfını genişleten özel bir sınıf oluşturun.
  2. newApplication işlevini geçersiz kılın ve oluşturulan Hilt test uygulamasının adını iletin.
// A custom runner to set up the instrumented application class for tests.
class CustomTestRunner : AndroidJUnitRunner() {

    override fun newApplication(cl: ClassLoader?, name: String?, context: Context?): Application {
        return super.newApplication(cl, HiltTestApplication::class.java.name, context)
    }
}

Ardından, bu test çalıştırıcıyı Gradle dosyanızda Araçlı birim testi kılavuzunda açıklandığı şekilde yapılandırın. Tam sınıf yolunu kullandığınızdan emin olun:

android {
    defaultConfig {
        // Replace com.example.android.dagger with your class path.
        testInstrumentationRunner = "com.example.android.dagger.CustomTestRunner"
    }
}
Robolectric testlerinde test uygulamasını ayarlama

Kullanıcı arayüzü katmanınızı test etmek için Robolectric kullanıyorsanız robolectric.properties dosyasında hangi uygulamanın kullanılacağını belirtebilirsiniz:

application = dagger.hilt.android.testing.HiltTestApplication

Alternatif olarak, Robolectric'in @Config ek açıklamasını kullanarak uygulamayı her testte ayrı ayrı yapılandırabilirsiniz:

@HiltAndroidTest
@Config(application = HiltTestApplication::class)
class SettingsScreenTest {

  @get:Rule
  var hiltRule = HiltAndroidRule(this)

  // Robolectric tests here.
}

Test özellikleri

Hilt, testlerinizde kullanılmaya hazır olduğunda test sürecini özelleştirmek için çeşitli özelliklerden yararlanabilirsiniz.

Testlerde türleri ekleme

Türleri bir teste yerleştirmek için alan yerleştirme amacıyla @Inject kullanın. Hilt'e @Inject alanlarını doldurmasını söylemek için hiltRule.inject() yöntemini çağırın.

Aşağıdaki enstrümantasyon testi örneğine bakın:

@HiltAndroidTest
class SettingsScreenTest {

    @get:Rule(order = 0)
    val hiltRule = HiltAndroidRule(this)

    @get:Rule(order = 1)
    val composeRule = createAndroidComposeRule<HiltTestActivity>()

    @Inject
    lateinit var analyticsAdapter: AnalyticsAdapter

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

    @Test
    fun settingsScreen_showsTitle() {
        composeRule.setContent {
            SettingsScreen()
        }
        composeRule.onNodeWithText("Settings").assertIsDisplayed()
        // analyticsRepository is available here.
    }
}

Bağlamayı değiştirme

Bir bağımlılığın sahte veya taklit örneğini yerleştirmeniz gerekiyorsa Hilt kitaplığına, canlı sürüm kodunda kullandığı bağlamayı kullanmamasını ve bunun yerine farklı bir bağlama kullanmasını söylemeniz gerekir. Bir bağlamayı değiştirmek için bağlamayı içeren modülü, testte kullanmak istediğiniz bağlamaları içeren bir test modülüyle değiştirmeniz gerekir.

Örneğin, üretim kodunuzun AnalyticsService için aşağıdaki gibi bir bağlama bildirdiğini varsayalım:

@Module
@InstallIn(SingletonComponent::class)
abstract class AnalyticsModule {

  @Singleton
  @Binds
  abstract fun bindAnalyticsService(
    analyticsServiceImpl: AnalyticsServiceImpl
  ): AnalyticsService
}

Testlerde AnalyticsService bağlamasını değiştirmek için test veya androidTest klasöründe sahte bağımlılık içeren yeni bir Hilt modülü oluşturun ve bu modülü @TestInstallIn ile ek açıklama ekleyin. Bunun yerine, o klasördeki tüm testlere sahte bağımlılık eklenir.

@Module
@TestInstallIn(
    components = [SingletonComponent::class],
    replaces = [AnalyticsModule::class]
)
abstract class FakeAnalyticsModule {

  @Singleton
  @Binds
  abstract fun bindAnalyticsService(
    fakeAnalyticsService: FakeAnalyticsService
  ): AnalyticsService
}

Birleştirilebilir öğeler genellikle bu bağımlılıkları hiltViewModel() ile elde edilen bir ViewModel aracılığıyla dolaylı olarak kullandığından Hilt kitaplığındaki bağlamayı değiştirmek yeterlidir. Test edilen composable, sahte nesneyi otomatik olarak alır.

Tek bir testte bağlamayı değiştirme

Bir bağlamayı tüm testler yerine tek bir testte değiştirmek için @UninstallModules ek açıklamasını kullanarak bir Hilt modülünü testten kaldırın ve testin içinde yeni bir test modülü oluşturun.

Önceki sürümdeki AnalyticsService örneğini kullanarak test sınıfında @UninstallModules ek açıklamasını kullanarak Hilt'e üretim modülünü yoksaymasını söyleyin:

@UninstallModules(AnalyticsModule::class)
@HiltAndroidTest
class SettingsScreenTest { ... }

Ardından, bağlamayı değiştirmeniz gerekir. Test sınıfı içinde, test bağlamayı tanımlayan yeni bir modül oluşturun:

@UninstallModules(AnalyticsModule::class)
@HiltAndroidTest
class SettingsScreenTest {

  @Module
  @InstallIn(SingletonComponent::class)
  abstract class TestModule {

    @Singleton
    @Binds
    abstract fun bindAnalyticsService(
      fakeAnalyticsService: FakeAnalyticsService
    ): AnalyticsService
  }

  // ...
}

Bu işlem yalnızca tek bir test sınıfının bağlamasını değiştirir. Tüm test sınıfları için bağlamayı değiştirmek istiyorsanız yukarıdaki bölümde yer alan @TestInstallIn ek açıklamasını kullanın. Alternatif olarak, test bağlamayı Robolectric testleri için test modülüne veya enstrümantasyon testleri için androidTest modülüne yerleştirebilirsiniz. Mümkün olduğunda @TestInstallIn kullanmanız önerilir.

Yeni değerler bağlanıyor

Testinizdeki alanları Hilt bağımlılık grafiğine kolayca bağlamak için @BindValue ek açıklamasını kullanın. Bir alanı @BindValue ile ek açıklama eklediğinizde, bu alan, bildirilen alan türü altında, o alan için mevcut olan tüm niteleyicilerle birlikte bağlanır.

AnalyticsService örneğinde, @BindValue kullanarak AnalyticsService öğesini sahte bir öğeyle değiştirebilirsiniz:

@UninstallModules(AnalyticsModule::class)
@HiltAndroidTest
class SettingsScreenTest {

  @BindValue @JvmField
  val analyticsService: AnalyticsService = FakeAnalyticsService()

  ...
}

Bu sayede, testinizde bir bağlamayı değiştirme ve bağlamaya referans verme işlemlerini aynı anda yapabilirsiniz.

@BindValue, niteleyiciler ve diğer test ek açıklamalarıyla çalışır. Örneğin, Mockito gibi test kitaplıkları kullanıyorsanız bunu Robolectric testinde şu şekilde kullanabilirsiniz:

...
class SettingsScreenTest {
  ...

  @BindValue @ExampleQualifier @Mock
  lateinit var qualifiedVariable: ExampleCustomType

  // Robolectric tests here
}

Çoklu bağlama eklemeniz gerekiyorsa @BindValue yerine @BindValueIntoSet ve @BindValueIntoMap ek açıklamalarını kullanabilirsiniz. @BindValueIntoMap, alanı bir harita anahtarı ek açıklamasıyla da açıklama eklemenizi gerektirir.

Özel durumlar

Hilt, standart dışı kullanım alanlarını destekleyen özellikler de sunar.

Testler için özel uygulama

Test uygulamanızın başka bir uygulamayı genişletmesi gerektiği için HiltTestApplication öğesini kullanamıyorsanız yeni bir sınıfı veya arayüzü @CustomTestApplication ile ek açıklama ekleyerek oluşturulan Hilt uygulamasının genişletmesini istediğiniz temel sınıfın değerini iletin.

@CustomTestApplication, parametre olarak ilettiğiniz uygulamayı genişleten ve Hilt ile test edilmeye hazır bir Application sınıfı oluşturur.

@CustomTestApplication(BaseApplication::class)
interface HiltTestApplication

Örnekte Hilt, BaseApplication sınıfını genişleten HiltTestApplication_Application adlı bir Application oluşturur. Genel olarak, oluşturulan uygulamanın adı, ek açıklamalı sınıfın adının sonuna _Application eklenmiş halidir. Oluşturulan Hilt test uygulamasını, Test uygulaması bölümünde açıklandığı gibi enstrümantasyon testlerinizde veya Robolectric testlerinizde çalışacak şekilde ayarlamanız gerekir.

Enstrümantasyon testinizde birden fazla TestRule nesnesi

Compose kullanıcı arayüzü testleri, HiltAndroidRule ile createAndroidComposeRule gibi bir Compose test kuralını zaten birleştirir. Başka TestRule nesneleriniz varsa önce HiltAndroidRule nesnesinin çalıştığından emin olun. @Rule üzerinde order özelliğiyle yürütme sırasını bildirin:

@HiltAndroidTest
class SettingsScreenTest {

  @get:Rule(order = 0)
  var hiltRule = HiltAndroidRule(this)

  @get:Rule(order = 1)
  val composeRule = createAndroidComposeRule<HiltTestActivity>()

  @get:Rule(order = 2)
  val otherRule = SomeOtherRule()

  // UI tests here.
}

Alternatif olarak, kuralları RuleChain ile sarmalayarak HiltAndroidRule kuralını dış kural olarak yerleştirebilirsiniz.

@HiltAndroidTest
class SettingsScreenTest {

  @get:Rule
  var rule = RuleChain.outerRule(HiltAndroidRule(this)).
        around(SettingsScreenTestRule(...))

  // UI tests here.
}

Tekil bileşen kullanılabilir olmadan önce bir giriş noktası kullanın

@EarlyEntryPoint ek açıklaması, bir Hilt testinde tekil bileşen kullanılabilir olmadan önce Hilt giriş noktası oluşturulması gerektiğinde bir çıkış yolu sağlar.

@EarlyEntryPoint hakkında daha fazla bilgi için Hilt belgelerine göz atın.

Ek kaynaklar

Test hakkında daha fazla bilgi edinmek için aşağıdaki ek kaynaklara göz atın:

Belgeler

İçerik görüntüleme