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'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 bir sınıf oluşturucuyu çağırabilirsiniz. Bu işlemi, oluşturucu 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 sahte verilerle 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 uygulamak 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 kümenizde HiltTestActivity adlı boş bir etkinlik oluşturmanız ve bunu @AndroidEntryPoint ile 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 bölümüne bakın.
Test uygulamanızı enstrümanlı testlerinizde veya Robolectric testlerinizde çalışacak şekilde ayarlamanız gerekir. Aşağıdaki talimatlar Hilt'e özel değildir ancak testlerde çalıştırılacak özel bir uygulamayı belirtme konusunda genel yönergeler sunar.
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ümantasyon testlerinde ç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, Enstrümanlı birim testi kılavuzunda açıklandığı gibi bu test çalıştırıcıyı 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 kitaplığına ü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 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 ek açıklama olarak belirtin. 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
Tüm testler yerine tek bir testte bağlamayı 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 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, aynı anda her ikisini de yapmanıza olanak tanıyarak hem bağlamayı değiştirmeyi hem de testinizde bağlamaya referans vermeyi kolaylaştırır.
@BindValue, niteleyiciler ve diğer test açıklamalarıyla çalışır. Örneğin, Mockito gibi test kitaplıkları kullanıyorsanız bunu 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ı ek 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
, yeni bir sınıfı veya arayüzü ile açıklama eklemesi gerektiğinden HiltTestApplication'yı kullanamıyorsanız
oluşturulan Hilt uygulamasının genişletmesini istediğiniz temel sınıfın değerini ileterek
@CustomTestApplication ile yeni bir sınıf veya arayüz açıklama ekleyin.
@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ı
HiltTestApplication_Application bir sınıf oluşturur. 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 giriş noktası Hilt testinde tekil bileşen kullanılabilir hale gelmeden önce oluşturulması gerektiğinde bir çı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 göz atın: