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 ekleme kullanan bir sınıfı test ederken bu sınıfı oluşturmak için Hilt'i kullanmanız gerekmediğinden birim testleri için Hilt gerekli değildir. Bunun yerine, oluşturucuya sahte veya taklit bağımlılıklar ileterek doğrudan sınıf oluşturucuyu çağırabilirsiniz. Bu işlemi, oluşturucuya açıklama eklenmemiş gibi yaparsınız:
@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 işlevlerinizde hiltViewModel() çağrılarak elde edilen ViewModel sınıfları için de geçerlidir. Birim testlerinde ViewModel'i doğrudan sahtelerle oluşturun.
Durumun ViewModel'den composable'lara nasıl aktığı hakkında bilgi edinmek için State ve Jetpack Compose ile Where to hoist state başlıklı makaleleri inceleyin.
Uçtan uca testler
Hilt, entegrasyon testleri için bağımlılıkları üretim kodunuzda olduğu gibi yerleştirir. Hilt ile test yaparken bakım gerekmez. Çü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'i kullanan tüm kullanıcı arayüzü testlerini @HiltAndroidTest ile açıklama eklemeniz gerekir. Bu
ek açıklama, her test için Hilt bileşenlerini oluşturmaktan sorumludur.
Ayrıca, HiltAndroidRule öğesini test sınıfına eklemeniz gerekir. Bileşenlerin durumunu yönetir ve testinize ekleme işlemi 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ı hakkında bilgi sahibi olması gerekir.
Hilt'in bağımlılıkları yerleştirmesine izin vermek için androidTest kaynak grubunuzda HiltTestActivity adlı boş bir etkinlik oluşturmanız ve bunu @AndroidEntryPoint ile ek açıklama eklemeniz gerekir. createAndroidComposeRule, bu etkinliği birleştirilebilir içeriğinizin barındırıcısı olarak kullanır.
Test uygulaması
Hilt'i kullanan enstrümanlı 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 başlıklı makaleyi inceleyin.
Test uygulamanızı enstrümanlı 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 uygulamayı belirtme ile ilgili genel yönergelerdir.
Enstrümanlı testlerde test uygulamasını ayarlama
Enstrümanlı testlerde Hilt test uygulamasını kullanmak için yeni bir test çalıştırıcı yapılandırmanız gerekir. Bu, Hilt'in projenizdeki tüm enstrümanlı testlerde çalışmasını sağlar. Aşağıdaki adımları uygulayın:
androidTestklasöründeAndroidJUnitRunneröğesini genişleten özel bir sınıf oluşturun.newApplicationiş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ı Enstrümanlı birim testi kılavuzunda açıklandığı şekilde Gradle dosyanızda 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'i 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.
Testlere tür yerleştirme
Bir teste tür yerleştirmek için alan yerleştirme işleminde @Inject kullanın. Hilt'e @Inject alanlarını doldurmasını söylemek için hiltRule.inject() işlevini çağırın.
Aşağıdaki enstrümanlı test ö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 edilmiş bir örneğini yerleştirmeniz gerekiyorsa Hilt'e üretim 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 }
Testlerdeki AnalyticsService bağlamasını değiştirmek için test veya androidTest klasöründe sahte bağımlılıkla yeni bir Hilt modülü oluşturun ve bu modülü @TestInstallIn ile açıklama ekleyin. Bunun yerine, söz konusu klasördeki tüm testlere sahte bağımlılık yerleştirilir.
@Module @TestInstallIn( components = [SingletonComponent::class], replaces = [AnalyticsModule::class] ) abstract class FakeAnalyticsModule { @Singleton @Binds abstract fun bindAnalyticsService( fakeAnalyticsService: FakeAnalyticsService ): AnalyticsService }
Composable'lar genellikle bu bağımlılıkları hiltViewModel() ile elde edilen bir ViewModel aracılığıyla dolaylı olarak kullandığından Hilt'teki bağlamayı değiştirmek yeterlidir. Test edilen composable, sahteyi 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.
AnalyticsServiceÖnceki sürümdeki örneği@UninstallModules izleyerek test sınıfında @UninstallModules ek açıklamasını kullanarak Hilt'e üretim modülünü yoksaymasını söyleyerek başlayın:
@UninstallModules(AnalyticsModule::class) @HiltAndroidTest class SettingsScreenTest { ... }
Ardından, bağlamayı değiştirmeniz gerekir. Test sınıfında test bağlamasını 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ının bağlamasını değiştirmek istiyorsanız yukarıdaki bölümdeki @TestInstallIn ek açıklamasını kullanın. Alternatif olarak, test bağlamasını Robolectric testleri için test modülüne veya enstrümanlı testler için androidTest modülüne yerleştirebilirsiniz.
Mümkün olduğunda @TestInstallIn kullanılması önerilir.
Yeni değerleri bağlama
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 açıklama eklediğinizde, bu alan, belirtilen alan türü altında ve bu alan için mevcut olan tüm niteleyicilerle birlikte bağlanır.
AnalyticsService örneğinde, AnalyticsService yerine @BindValue kullanarak sahte bir değer girebilirsiniz:
@UninstallModules(AnalyticsModule::class) @HiltAndroidTest class SettingsScreenTest { @BindValue @JvmField val analyticsService: AnalyticsService = FakeAnalyticsService() ... }
Bu, hem bağlamayı değiştirmenizi hem de testinizde bağlamaya referans vermenizi aynı anda yapmanıza olanak tanıyarak her iki işlemi de basitleştirir.
@BindValue, niteleyicilerle ve diğer test açıklamalarıyla çalışır. Örneğin, Mockito gibi test kitaplıkları kullanıyorsanız bunu bir Robolectric testinde aşağıdaki gibi 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ı açıklamasıyla da açıklamanızı gerektirir.
Özel durumlar
Hilt, standart dışı kullanım alanlarını destekleyecek özellikler de sunar.
Testler için özel uygulama
Test uygulamanızın başka bir uygulamayı genişletmesi gerektiği için HiltTestApplication kullanamıyorsanız @CustomTestApplication ile yeni bir sınıf veya arayüz ekleyin. 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, 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 Application adlı bir sınıf oluşturur.HiltTestApplication_Application Genel olarak, oluşturulan uygulamanın adı, _Application ile eklenmiş açıklama eklenmiş sınıfın adıdır. Oluşturulan Hilt test uygulamasını, Test uygulaması bölümünde açıklandığı gibi enstrümanlı testlerinizde veya Robolectric testlerinizde çalışacak şekilde ayarlamanız gerekir.
Araçlı 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 HiltAndroidRule'nin önce çalıştığından emin olun. @Rule öğesinde order özelliğiyle yürütme sırasını beyan edin:
@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 sarmalayabilir ve HiltAndroidRule öğesini dış kural olarak yerleştirebilirsiniz.
@HiltAndroidTest class SettingsScreenTest { @get:Rule var rule = RuleChain.outerRule(HiltAndroidRule(this)). around(SettingsScreenTestRule(...)) // UI tests here. }
Singleton bileşeni kullanıma sunulmadan önce bir giriş noktası kullanma
@EarlyEntryPoint ek açıklaması, Hilt testinde tekil bileşen kullanıma sunulmadan önce bir Hilt giriş noktası oluşturulması gerektiğinde çıkış yolu sağlar.
@EarlyEntryPoint hakkında daha fazla bilgiyi Hilt belgelerinde bulabilirsiniz.
Ek kaynaklar
Test hakkında daha fazla bilgi edinmek için aşağıdaki ek kaynaklara bakın: