Hilt gibi bağımlılık yerleştirme çerçeveleri kullanmanın avantajlarından biri, kodunuzu test etmeyi kolaylaştırmasıdır.
Ünite testleri
Yapıcı 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, oluşturucuya ek açıklama eklenmediği zaman yaptığınız gibi, sahte veya sahte bağımlılıkları ileterek bir sınıf kurucusunu doğrudan ç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
Entegrasyon testleri için Hilt, bağımlılıkları üretim kodunuzda olduğu gibi ekler. Hilt, her test için otomatik olarak yeni bir bileşen grubu oluşturduğundan Hilt ile test etmek bakım gerektirmez.
Test bağımlılıkları ekleme
Testlerinizde Hilt'i kullanmak için projenize hilt-android-testing
bağımlılığını dahil edin:
Modern
dependencies { // For Robolectric tests. testImplementation 'com.google.dagger:hilt-android-testing:2.44' // ...with Kotlin. kaptTest 'com.google.dagger:hilt-android-compiler:2.44' // ...with Java. testAnnotationProcessor 'com.google.dagger:hilt-android-compiler:2.44' // For instrumented tests. androidTestImplementation 'com.google.dagger:hilt-android-testing:2.44' // ...with Kotlin. kaptAndroidTest 'com.google.dagger:hilt-android-compiler:2.44' // ...with Java. androidTestAnnotationProcessor 'com.google.dagger:hilt-android-compiler:2.44' }
Kotlin
dependencies { // For Robolectric tests. testImplementation("com.google.dagger:hilt-android-testing:2.44") // ...with Kotlin. kaptTest("com.google.dagger:hilt-android-compiler:2.44") // ...with Java. testAnnotationProcessor("com.google.dagger:hilt-android-compiler:2.44") // For instrumented tests. androidTestImplementation("com.google.dagger:hilt-android-testing:2.44") // ...with Kotlin. kaptAndroidTest("com.google.dagger:hilt-android-compiler:2.44") // ...with Java. androidTestAnnotationProcessor("com.google.dagger:hilt-android-compiler:2.44") }
Kullanıcı arayüzü test kurulumu
Hilt'i kullanan tüm kullanıcı arayüzü testlerine @HiltAndroidTest
ile ek açıklama eklemeniz gerekir. Bu ek açıklama, her bir 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 yerleştirme 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. }
Sonraki adımda, testinizin, Hilt'in sizin için otomatik olarak oluşturduğu Application
sınıfı hakkında bilgi edinmesi 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ünü inceleyin.
Test uygulamanızı araçlı 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çlı testlerde test uygulamasını ayarlama
Hilt test uygulamasını araçlı testlerde kullanmak için yeni bir test çalıştırıcı yapılandırmanız gerekir. Bu, Hilt'in projenizdeki tüm aletli testlerde çalışmasını sağlar. Aşağıdaki adımları uygulayın:
androidTest
klasöründeAndroidJUnitRunner
öğesini 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); } }
Daha sonra, bu test çalıştırıcısını Gradle dosyanızda, araçlı birim test kılavuzunda açıklandığı gibi yapılandırın. Sınıf yolunun tamamını kullandığınızdan emin olun:
Modern
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ırsanı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 tek tek 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. }
Android Gradle Eklentisi'nin 4.2'den önceki bir sürümünü 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:
Modern
hilt { enableTransformForLocalTests = true }
Kotlin
hilt { enableTransformForLocalTests = true }
enableTransformForLocalTests
hakkında daha fazla bilgiyi Hilt belgelerinde bulabilirsiniz.
Test özellikleri
Hilt testlerinizde kullanılmaya hazır hale geldiğinde test sürecini özelleştirmek için çeşitli özellikleri kullanabilirsiniz.
Testlere ekleme türleri
Bir teste tür eklemek için alan yerleştirme için @Inject
kullanın. Hilt'e @Inject
alanlarını doldurmasını bildirmek için hiltRule.inject()
yöntemini çağırın.
Aşağıdaki araçlı test örneğini inceleyin:
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
Bağımlılığın sahte veya sahte bir örneğini eklemeniz gerekirse Hilt'e, üretim kodunda kullandığı bağlamayı kullanmamasını ve bunun yerine farklı bir bağlantı kullanmasını bildirmeniz 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 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ğlantısı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üle @TestInstallIn
ifadesiyle ek açıklama ekleyin. Bunun yerine, bu klasördeki tüm testlere sahte bağımlılık eklenir.
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 testte bağlamayı değiştirme
Tüm testler yerine tek bir testteki bağlamayı değiştirmek için @UninstallModules
ek açıklamasını kullanarak bir testten Hilt modülünü kaldırın ve test içinde yeni bir test modülü oluşturun.
Önceki sürümdeki AnalyticsService
örneğine göre, test sınıfında @UninstallModules
ek açıklamasını kullanarak Hilt'e üretim modülünü yoksaymasını bildirerek işe başlayın:
Kotlin
@UninstallModules(AnalyticsModule::class) @HiltAndroidTest class SettingsActivityTest { ... }
Java
@UninstallModules(AnalyticsModule.class) @HiltAndroidTest public final class SettingsActivityTest { ... }
Ardından, bağlantıyı değiştirmeniz gerekir. Test sınıfı içinde, 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, yalnızca tek bir test sınıfının bağlamasının yerini alır. Bağlamayı tüm test sınıfları için değiştirmek istiyorsanız yukarıdaki bölümde yer alan @TestInstallIn
ek açıklamasını kullanın. Alternatif olarak, test bağlamasını Robolectric testler için test
modülüne veya araçlı testler için androidTest
modülüne yerleştirebilirsiniz.
Mümkün olduğunda @TestInstallIn
kullanmanızı öneririz.
Yeni değerler bağlama
Testinizdeki alanları Hilt bağımlılık grafiğine kolayca bağlamak için @BindValue
ek açıklamasını kullanın. @BindValue
ile alana ek açıklama eklediğinizde, alan, söz konusu alan için mevcut olan niteleyicilerle birlikte bildirilen alan türünün altına bağlanır.
AnalyticsService
örneğinde, @BindValue
kullanarak AnalyticsService
yerine sahte bir dosya koyabilirsiniz:
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 yöntem, aynı anda ikisini aynı anda yapabilmenizi sağlayarak hem bağlamayı değiştirmeyi hem de testinizde bağlamaya referans vermeyi kolaylaştırır.
@BindValue
, niteleyiciler ve diğer test ek açıklamalarıyla çalışır. Örneğin, Mockito gibi test kitaplıkları kullanıyorsanız bunu bir Robolectric testinde aşağıdaki şekilde 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 gerekirse @BindValue
yerine @BindValueIntoSet
ve @BindValueIntoMap
ek açıklamalarını kullanabilirsiniz. @BindValueIntoMap
, alana bir eşleme anahtarı ek açıklaması da 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ğinden HiltTestApplication
öğesini kullanamıyorsanız yeni bir sınıfa veya arayüze @CustomTestApplication
ek açıklaması ekleyin ve oluşturulan Hilt uygulamasının kapsamını genişletmesini istediğiniz temel sınıfın değerini aktarın.
@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 HiltTestApplication_Application
adlı bir Application
oluşturur. Genel olarak oluşturulan uygulamanın adı, sonuna _Application
eklenmiş ek açıklamalı sınıfın adıdır. Oluşturulan Hilt test uygulamasını, Test uygulaması bölümünde açıklandığı gibi araçlı testlerinizde veya Robolectric testlerinizde çalışacak şekilde ayarlamanız gerekir.
Araçlı testinizde birden fazla TestRule nesnesi
Testinizde başka TestRule
nesneleri varsa tüm kuralların birlikte çalıştığından emin olmanın birden fazla 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, HiltAndroidRule
önce yürütüldüğü sürece her iki kuralı da aynı düzeyde kullanabilirsiniz. @Rule
ek açıklamasındaki order
özelliğini kullanarak yürütme sırasını belirtin. Bu 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'ı
androidx.fragment:fragment-testing
kitaplığındaki launchFragmentInContainer
, @AndroidEntryPoint
ile ek açıklama girilmemiş bir etkinliğe dayandığından Hilt ile kullanılamaz.
Bunun yerine, architecture-samples
GitHub deposundaki launchFragmentInHiltContainer
kodunu kullanın.
Singleton bileşeni kullanıma sunulmadan önce bir giriş noktası kullanın
@EarlyEntryPoint
ek açıklaması, tekil bileşen bileşeni bir Hilt testinde kullanıma sunulmadan önce Hilt giriş noktasının oluşturulması gerektiğinde bir çıkış yolu sağlar.
@EarlyEntryPoint
hakkında daha fazla bilgiyi Hilt belgelerinde bulabilirsiniz.