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:
Kotlin
@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(...) } }
Java
@ActivityScope public class AnalyticsAdapter { private final AnalyticsService analyticsService; @Inject AnalyticsAdapter(AnalyticsService analyticsService) { this.analyticsService = analyticsService; } } public final class AnalyticsAdapterTest { @Test public void happyPath() { // You don't need Hilt to create an instance of AnalyticsAdapter. // You can pass a fake or mock AnalyticsService. AnalyticsAdapter adapter = new AnalyticsAdapter(fakeAnalyticsService); assertEquals(...); } }
Uçtan uca testler
Hilt, entegrasyon testleri için bağımlılıkları üretim kodunuzda olduğu gibi yerleştirir. Hilt ile test yapmak için 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:
Groovy
dependencies { // For Robolectric tests. testImplementation 'com.google.dagger:hilt-android-testing:2.57.1' // ...with Kotlin. kaptTest 'com.google.dagger:hilt-android-compiler:2.57.1' // ...with Java. testAnnotationProcessor 'com.google.dagger:hilt-android-compiler:2.57.1' // For instrumented tests. androidTestImplementation 'com.google.dagger:hilt-android-testing:2.57.1' // ...with Kotlin. kaptAndroidTest 'com.google.dagger:hilt-android-compiler:2.57.1' // ...with Java. androidTestAnnotationProcessor 'com.google.dagger:hilt-android-compiler:2.57.1' }
Kotlin
dependencies { // For Robolectric tests. testImplementation("com.google.dagger:hilt-android-testing:2.57.1") // ...with Kotlin. kaptTest("com.google.dagger:hilt-android-compiler:2.57.1") // ...with Java. testAnnotationProcessor("com.google.dagger:hilt-android-compiler:2.57.1") // For instrumented tests. androidTestImplementation("com.google.dagger:hilt-android-testing:2.57.1") // ...with Kotlin. kaptAndroidTest("com.google.dagger:hilt-android-compiler:2.57.1") // ...with Java. androidTestAnnotationProcessor("com.google.dagger:hilt-android-compiler:2.57.1") }
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:
Kotlin
@HiltAndroidTest class SettingsActivityTest { @get:Rule var hiltRule = HiltAndroidRule(this) // UI tests here. }
Java
@HiltAndroidTest public final class SettingsActivityTest { @Rule public HiltAndroidRule hiltRule = new HiltAndroidRule(this); // 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.
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. 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ü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.
Kotlin
// 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) } }
Java
// A custom runner to set up the instrumented application class for tests. public final class CustomTestRunner extends AndroidJUnitRunner { @Override public Application newApplication(ClassLoader cl, String className, Context context) throws ClassNotFoundException, IllegalAccessException, InstantiationException { return super.newApplication(cl, HiltTestApplication.class.getName(), 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:
Groovy
android { defaultConfig { // Replace com.example.android.dagger with your class path. testInstrumentationRunner "com.example.android.dagger.CustomTestRunner" } }
Kotlin
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:
Kotlin
@HiltAndroidTest @Config(application = HiltTestApplication::class) class SettingsActivityTest { @get:Rule var hiltRule = HiltAndroidRule(this) // Robolectric tests here. }
Java
@HiltAndroidTest @Config(application = HiltTestApplication.class) class SettingsActivityTest { @Rule public HiltAndroidRule hiltRule = new HiltAndroidRule(this); // Robolectric tests here. }
4.2'den eski bir Android Gradle Plugin sürümü kullanıyorsanız modülünüzün build.gradle dosyasına aşağıdaki yapılandırmayı uygulayarak yerel birim testlerinde @AndroidEntryPoint sınıflarının dönüştürülmesini etkinleştirin:
Groovy
hilt { enableTransformForLocalTests = true }
Kotlin
hilt { enableTransformForLocalTests = true }
enableTransformForLocalTests hakkında daha fazla bilgiyi Hilt belgelerinde bulabilirsiniz.
Test özellikleri
Hilt, testlerinizde kullanılmaya hazır olduğunda test sürecini özelleştirmek için çeşitli özelliklerden yararlanabilirsiniz.
Testlere tür ekleme
Bir teste tür eklemek için alan ekleme 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:
Kotlin
@HiltAndroidTest class SettingsActivityTest { @get:Rule var hiltRule = HiltAndroidRule(this) @Inject lateinit var analyticsAdapter: AnalyticsAdapter @Before fun init() { hiltRule.inject() } @Test fun `happy path`() { // Can already use analyticsAdapter here. } }
Java
@HiltAndroidTest public final class SettingsActivityTest { @Rule public HiltAndroidRule hiltRule = new HiltAndroidRule(this); @Inject AnalyticsAdapter analyticsAdapter; @Before public void init() { hiltRule.inject(); } @Test public void happyPath() { // Can already use analyticsAdapter 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 bağlama bildirdiğini varsayalım:
Kotlin
@Module @InstallIn(SingletonComponent::class) abstract class AnalyticsModule { @Singleton @Binds abstract fun bindAnalyticsService( analyticsServiceImpl: AnalyticsServiceImpl ): AnalyticsService }
Java
@Module @InstallIn(SingletonComponent.class) public abstract class AnalyticsModule { @Singleton @Binds public abstract AnalyticsService bindAnalyticsService( AnalyticsServiceImpl analyticsServiceImpl ); }
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.
Kotlin
@Module @TestInstallIn( components = [SingletonComponent::class], replaces = [AnalyticsModule::class] ) abstract class FakeAnalyticsModule { @Singleton @Binds abstract fun bindAnalyticsService( fakeAnalyticsService: FakeAnalyticsService ): AnalyticsService }
Java
@Module @TestInstallIn( components = SingletonComponent.class, replaces = AnalyticsModule.class ) public abstract class FakeAnalyticsModule { @Singleton @Binds public abstract AnalyticsService bindAnalyticsService( FakeAnalyticsService fakeAnalyticsService ); }
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 izleyerek test sınıfında @UninstallModules ek açıklamasını kullanarak Hilt'e üretim modülünü yoksaymasını söyleyin:
Kotlin
@UninstallModules(AnalyticsModule::class) @HiltAndroidTest class SettingsActivityTest { ... }
Java
@UninstallModules(AnalyticsModule.class) @HiltAndroidTest public final class SettingsActivityTest { ... }
Ardından, bağlamayı değiştirmeniz gerekir. Test bağlamasını tanımlayan test sınıfında yeni bir modül oluşturun:
Kotlin
@UninstallModules(AnalyticsModule::class) @HiltAndroidTest class SettingsActivityTest { @Module @InstallIn(SingletonComponent::class) abstract class TestModule { @Singleton @Binds abstract fun bindAnalyticsService( fakeAnalyticsService: FakeAnalyticsService ): AnalyticsService } ... }
Java
@UninstallModules(AnalyticsModule.class) @HiltAndroidTest public final class SettingsActivityTest { @Module @InstallIn(SingletonComponent.class) public abstract class TestModule { @Singleton @Binds public abstract AnalyticsService bindAnalyticsService( FakeAnalyticsService fakeAnalyticsService ); } ... }
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:
Kotlin
@UninstallModules(AnalyticsModule::class) @HiltAndroidTest class SettingsActivityTest { @BindValue @JvmField val analyticsService: AnalyticsService = FakeAnalyticsService() ... }
Java
@UninstallModules(AnalyticsModule.class) @HiltAndroidTest class SettingsActivityTest { @BindValue 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 notlarıyla çalışır. Örneğin, Mockito gibi test kitaplıkları kullanıyorsanız bunu bir Robolectric testinde aşağıdaki gibi kullanabilirsiniz:
Kotlin
... class SettingsActivityTest { ... @BindValue @ExampleQualifier @Mock lateinit var qualifiedVariable: ExampleCustomType // Robolectric tests here }
Java
... class SettingsActivityTest { ... @BindValue @ExampleQualifier @Mock ExampleCustomType qualifiedVariable; // 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 ek açıklama olarak işaretlemenizi 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ğinden 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.
Kotlin
@CustomTestApplication(BaseApplication::class) interface HiltTestApplication
Java
@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
Testinizde başka TestRule nesneler varsa tüm kuralların birlikte çalıştığından emin olmanın birden fazla yolu vardır.
Kuralları aşağıdaki şekilde birlikte sarmalayabilirsiniz:
Kotlin
@HiltAndroidTest class SettingsActivityTest { @get:Rule var rule = RuleChain.outerRule(HiltAndroidRule(this)). around(SettingsActivityTestRule(...)) // UI tests here. }
Java
@HiltAndroidTest public final class SettingsActivityTest { @Rule public RuleChain rule = RuleChain.outerRule(new HiltAndroidRule(this)) .around(new SettingsActivityTestRule(...)); // UI tests here. }
Alternatif olarak, HiltAndroidRule önce yürütüldüğü sürece her iki kuralı da aynı düzeyde kullanabilirsiniz. @Rule açıklamasında order özelliğini kullanarak yürütme sırasını belirtin. Bu özellik yalnızca JUnit 4.13 veya sonraki sürümlerinde çalışır:
Kotlin
@HiltAndroidTest class SettingsActivityTest { @get:Rule(order = 0) var hiltRule = HiltAndroidRule(this) @get:Rule(order = 1) var settingsActivityTestRule = SettingsActivityTestRule(...) // UI tests here. }
Java
@HiltAndroidTest public final class SettingsActivityTest { @Rule(order = 0) public HiltAndroidRule hiltRule = new HiltAndroidRule(this); @Rule(order = 1) public SettingsActivityTestRule settingsActivityTestRule = new SettingsActivityTestRule(...); // UI tests here. }
launchFragmentInContainer
launchFragmentInContainer, @AndroidEntryPoint ile açıklama eklenmemiş bir etkinliğe dayandığı için androidx.fragment:fragment-testing kitaplığındaki launchFragmentInContainer, Hilt ile kullanılamaz.
Bunun yerine architecture-samples GitHub deposundaki
launchFragmentInHiltContainer
kodunu kullanın.
Tekil bileşen 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.