Hilt gibi bağımlılık yerleştirme çerçevelerini kullanmanın avantajlarından biri, kodunuzu test etmeyi kolaylaştırmasıdır.
Birim testleri
Hilt, birim testleri için gerekli değildir. Çünkü yapıcı enjeksiyonu kullanan bir sınıfı test ederken sınıfı örneklemek için Hilt'i kullanmanız gerekmez. Bunun yerine, oluşturucuya açıklama eklenmediğinde olduğu gibi sahte veya sahte bağımlılıklar ileterek doğrudan bir sınıf oluşturucu çağırabilirsiniz:
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ını üretim kodunuzda olduğu gibi enjekte eder. Hilt her test için otomatik olarak yeni bir bileşen grubu oluşturduğundan Hilt ile test yapmak için bakım gerekmez.
Test bağımlılıkları ekleme
Hilt'i testlerinizde 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.51.1' // ...with Kotlin. kaptTest 'com.google.dagger:hilt-android-compiler:2.51.1' // ...with Java. testAnnotationProcessor 'com.google.dagger:hilt-android-compiler:2.51.1' // For instrumented tests. androidTestImplementation 'com.google.dagger:hilt-android-testing:2.51.1' // ...with Kotlin. kaptAndroidTest 'com.google.dagger:hilt-android-compiler:2.51.1' // ...with Java. androidTestAnnotationProcessor 'com.google.dagger:hilt-android-compiler:2.51.1' }
Kotlin
dependencies { // For Robolectric tests. testImplementation("com.google.dagger:hilt-android-testing:2.51.1") // ...with Kotlin. kaptTest("com.google.dagger:hilt-android-compiler:2.51.1") // ...with Java. testAnnotationProcessor("com.google.dagger:hilt-android-compiler:2.51.1") // For instrumented tests. androidTestImplementation("com.google.dagger:hilt-android-testing:2.51.1") // ...with Kotlin. kaptAndroidTest("com.google.dagger:hilt-android-compiler:2.51.1") // ...with Java. androidTestAnnotationProcessor("com.google.dagger:hilt-android-compiler:2.51.1") }
Kullanıcı arayüzü testi kurulumu
Hilt kullanan tüm kullanıcı arayüzü testlerine @HiltAndroidTest
ile not 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 testinizde ekleme 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 destekleyen bir Application
nesnesinde Hilt kullanan araçlı testler 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ı araçlarla 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 uygulamanın nasıl belirtileceğine dair genel yönergelerdir.
Araçla test edilen testlerde test uygulamasını ayarlama
Hilt test uygulamasını araçlarla test edilen testlerde kullanmak için yeni bir test çalıştırıcıyı yapılandırmanız gerekir. Bu sayede Hilt, projenizdeki tüm enstrümante testler için çalışır. Aşağıdaki adımları uygulayın:
androidTest
klasöründeAndroidJUnitRunner
uzantısını genişleten özel bir sınıf oluşturun.newApplication
iş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, Gradle dosyanızda bu test çalıştırıcısını donanım destekli birim testi kılavuzunda açıklandığı şekilde yapılandırın. Sınıf yolunun tamamını kullandığınızdan emin olun:
Eski
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 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 bir 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 Eklentisi sürümü kullanıyorsanız modülünüzün build.gradle
dosyasında aşağıdaki yapılandırmayı uygulayarak yerel birim testlerinde @AndroidEntryPoint
sınıflarını dönüştürmeyi etkinleştirin:
Groovy
hilt { enableTransformForLocalTests = true }
Kotlin
hilt { enableTransformForLocalTests = true }
enableTransformForLocalTests
hakkında daha fazla bilgiyi Hilt belgeleri bölümünde bulabilirsiniz.
Test özellikleri
Hilt, testlerinizde kullanıma hazır olduğunda test sürecini özelleştirmek için çeşitli özellikleri kullanabilirsiniz.
Testlere tür ekleme
Bir teste tür eklemek için alan ekleme için @Inject
kullanın. Hilt'e @Inject
alanlarını doldurmasını bildirmek için hiltRule.inject()
işlevini çağırın.
Aşağıdaki ölçülmüş 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ğlantıyı değiştirme
Bir bağımlılığın sahte veya taklit örneğini eklemeniz 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 bir bağlamayı aşağıdaki gibi tanımladığını 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ığı olan yeni bir Hilt modülü oluşturun ve @TestInstallIn
ile ek açıklama ekleyin. Bunun yerine, söz konusu klasördeki tüm testler sahte bağımlılıkla enjekte edilir.
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 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 takip ederek, test sınıfında @UninstallModules
ek açıklamasını kullanarak Hilt'e üretim modülünü yoksamasını söyleyerek başlayın:
Kotlin
@UninstallModules(AnalyticsModule::class) @HiltAndroidTest class SettingsActivityTest { ... }
Java
@UninstallModules(AnalyticsModule.class) @HiltAndroidTest public final class SettingsActivityTest { ... }
Ardından, cilt kapağını değiştirmeniz gerekir. Test sınıfında, test bağlamasını tanımlayan 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ümante edilmiş testler için androidTest
modülüne yerleştirebilirsiniz.
Mümkün olduğunda @TestInstallIn
kullanmanızı öneririz.
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 alana @BindValue
ile ek açıklama eklediğinizde, bu alan, belirtilen alan türünün altına, o alanda bulunan tüm niteliklerle birlikte bağlanır.
AnalyticsService
örneğinde, @BindValue
kullanarak AnalyticsService
değerini sahte bir değerle değiştirebilirsiniz:
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, her ikisini de aynı anda yapmanıza olanak tanıyarak hem testinizde bir bağlamayı değiştirmeyi hem de bağlamaya referans vermeyi kolaylaştırır.
@BindValue
, nitelikler ve diğer test ek açıklamalarıyla çalışır. Örneğin, Mockito gibi test kitaplıklarını kullanıyorsanız bunu 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
, alana bir harita anahtarı ek açıklaması da eklemenizi 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 oluşturulan Hilt uygulamasının genişletmesini istediğiniz temel sınıfın değerini ileterek yeni bir sınıfı veya arayüzü @CustomTestApplication
ile ek açıklamayla belirtin.
@CustomTestApplication
, Hilt ile parametre olarak ilettiğiniz uygulamayı genişleten ve teste hazır bir Application
sınıfı oluşturur.
Kotlin
@CustomTestApplication(BaseApplication::class) interface HiltTestApplication
Java
@CustomTestApplication(BaseApplication.class) interface HiltTestApplication { }
Aşağıdaki örnekte Hilt, BaseApplication
sınıfını genişleten HiltTestApplication_Application
adlı bir Application
oluşturur. Genel olarak, oluşturulan uygulamanın adı _Application
ile eklenen açıklama eklenen sınıfın adıdır. Oluşturulan Hilt test uygulamasını, Test uygulaması bölümünde açıklandığı gibi araçlarla testlerinizde veya Robolectric testlerinizde çalıştıracak şekilde ayarlamanız gerekir.
Araçla test edilen testinizde birden fazla TestRule nesnesi
Testinizde başka TestRule
nesneleri varsa tüm kuralların birlikte çalışmasını sağlamanın birden çok yolu vardır.
Kuralları aşağıdaki gibi bir araya getirebilirsiniz:
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, önce HiltAndroidRule
yürütüldüğü sürece her iki kuralı da aynı düzeyde kullanabilirsiniz. @Rule
ek açıklamalarında order
özelliğini kullanarak yürütme sırasını belirtin. Bu yöntem yalnızca JUnit 4.13 veya sonraki sürümlerde ç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
Hilt, @AndroidEntryPoint
ile ek açıklama eklenmemiş bir etkinliğe dayandığı için androidx.fragment:fragment-testing
kitaplığındaki launchFragmentInContainer
öğesini Hilt ile kullanmak mümkün değildir.
Bunun yerine architecture-samples
GitHub deposundaki launchFragmentInHiltContainer
kodunu kullanın.
Singleton bileşeni kullanılabilir hale gelmeden önce bir giriş noktası kullanın
@EarlyEntryPoint
ek açıklama, Hilt testinde tekil bileşen kullanılabilir hale gelmeden önce Hilt giriş noktası oluşturulması gerektiğinde bir kaçış yolu sağlar.
@EarlyEntryPoint
hakkında daha fazla bilgi için Hilt belgelerine göz atın.