Salah satu manfaat menggunakan framework injeksi dependensi seperti Hilt adalah memudahkan Anda menguji kode.
Pengujian Unit
Hilt tidak diperlukan untuk pengujian unit karena saat menguji class yang menggunakan injeksi konstruktor, Anda tidak perlu menggunakan Hilt untuk membuat instance class tersebut. Sebaliknya, Anda dapat langsung memanggil konstruktor class dengan meneruskan dependensi tiruan atau palsu, sama seperti yang akan Anda lakukan jika konstruktor tidak dianotasi:
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(...); } }
Pengujian menyeluruh
Untuk pengujian integrasi, Hilt menginjeksikan dependensi seperti yang terjadi pada kode produksi Anda. Pengujian dengan Hilt tidak memerlukan pemeliharaan karena Hilt otomatis menghasilkan serangkaian komponen baru untuk setiap pengujian.
Menambahkan dependensi pengujian
Untuk menggunakan Hilt dalam pengujian, sertakan dependensi hilt-android-testing
dalam project
Anda:
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") }
Penyiapan pengujian UI
Anda harus menganotasi setiap pengujian UI yang menggunakan Hilt dengan @HiltAndroidTest
. Anotasi
ini bertanggung jawab untuk menghasilkan komponen Hilt untuk setiap pengujian.
Selain itu, Anda perlu menambahkan HiltAndroidRule
ke class pengujian. Fitur ini mengelola
status komponen dan digunakan untuk melakukan injeksi pada pengujian Anda:
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. }
Selanjutnya, pengujian Anda perlu mengetahui class Application
yang otomatis dihasilkan
Hilt untuk Anda.
Aplikasi pengujian
Anda harus menjalankan uji instrumentasi yang menggunakan Hilt pada objek Application
yang mendukung Hilt. Library ini menyediakan HiltTestApplication
untuk digunakan dalam pengujian.
Jika pengujian memerlukan aplikasi dasar berbeda, lihat Aplikasi kustom untuk
pengujian.
Anda harus menetapkan aplikasi pengujian untuk dijalankan dalam uji instrumentasi atau uji Robolectric. Petunjuk berikut tidak khusus untuk Hilt, tetapi merupakan panduan umum cara menentukan aplikasi kustom yang akan dijalankan dalam pengujian.
Menetapkan aplikasi pengujian dalam uji instrumentasi
Untuk menggunakan aplikasi pengujian Hilt dalam uji instrumentasi, Anda perlu mengonfigurasi runner pengujian baru. Hal ini membuat Hilt berfungsi untuk semua uji instrumentasi dalam project Anda. Lakukan langkah-langkah berikut:
- Buat class kustom yang memperluas
AndroidJUnitRunner
di folderandroidTest
. - Ganti fungsi
newApplication
dan teruskan dengan nama aplikasi pengujian Hilt yang dihasilkan.
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); } }
Selanjutnya, konfigurasikan runner pengujian ini dalam file Gradle Anda seperti yang dijelaskan dalam panduan pengujian unit instrumentasi. Pastikan Anda menggunakan classpath penuh:
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" } }
Menetapkan aplikasi pengujian dalam uji Robolectric
Jika Anda menggunakan Robolectric untuk menguji lapisan UI, Anda dapat menentukan aplikasi
mana yang akan digunakan dalam file robolectric.properties
:
application = dagger.hilt.android.testing.HiltTestApplication
Atau, Anda dapat mengonfigurasi aplikasi satu per satu pada setiap pengujian menggunakan
anotasi @Config
Robolectric:
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. }
Jika Anda menggunakan Versi Plugin Android Gradle yang lebih rendah dari 4.2, aktifkan
transformasi class @AndroidEntryPoint
dalam pengujian unit lokal dengan menerapkan
konfigurasi berikut dalam file build.gradle
modul Anda:
Groovy
hilt { enableTransformForLocalTests = true }
Kotlin
hilt { enableTransformForLocalTests = true }
Informasi selengkapnya tentang enableTransformForLocalTests
ada dalam dokumentasi
Hilt.
Fitur Pengujian
Setelah Hilt siap digunakan dalam pengujian, Anda dapat menggunakan beberapa fitur untuk menyesuaikan proses pengujian.
Menginjeksikan jenis dalam pengujian
Untuk menginjeksikan jenis ke dalam pengujian, gunakan @Inject
untuk injeksi kolom. Untuk memberi tahu Hilt agar
mengisi kolom @Inject
, panggil hiltRule.inject()
.
Lihat contoh uji instrumentasi berikut:
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. } }
Mengganti binding
Jika Anda perlu menginjeksikan instance tiruan atau palsu dari dependensi, Anda perlu memberi tahu Hilt agar tidak menggunakan binding dalam kode produksi dan menggunakan yang lain. Untuk mengganti binding, Anda harus mengganti modul yang berisi binding, dengan modul pengujian berisi binding yang ingin digunakan dalam pengujian.
Misalnya, anggap kode produksi Anda mendeklarasikan binding untuk
AnalyticsService
sebagai berikut:
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 ); }
Untuk mengganti binding AnalyticsService
dalam pengujian, buat modul Hilt baru di
folder test
atau androidTest
dengan dependensi palsu dan anotasikan
dengan @TestInstallIn
. Sebagai gantinya, semua pengujian di folder tersebut dimasukkan dengan dependensi
palsu.
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 ); }
Mengganti binding di satu pengujian
Untuk mengganti binding di satu pengujian, bukan semua pengujian, uninstal modul
Hilt dari pengujian menggunakan anotasi @UninstallModules
dan buat
modul pengujian baru di dalam pengujian.
Dengan mengikuti contoh AnalyticsService
dari versi sebelumnya, mulailah dengan memberi tahu
Hilt untuk mengabaikan modul produksi menggunakan anotasi @UninstallModules
di class pengujian:
Kotlin
@UninstallModules(AnalyticsModule::class) @HiltAndroidTest class SettingsActivityTest { ... }
Java
@UninstallModules(AnalyticsModule.class) @HiltAndroidTest public final class SettingsActivityTest { ... }
Selanjutnya, Anda harus mengganti binding. Buat modul baru dalam class pengujian yang menentukan binding pengujian:
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 ); } ... }
Ini hanya menggantikan binding untuk satu class pengujian. Jika Anda ingin mengganti
binding untuk semua class pengujian, gunakan anotasi @TestInstallIn
dari
bagian di atas. Atau, Anda dapat memasukkan binding pengujian dalam modul test
untuk pengujian Robolectric, atau dalam modul androidTest
untuk uji instrumentasi.
Sebaiknya gunakan @TestInstallIn
jika memungkinkan.
Mengikatkan nilai baru
Gunakan anotasi @BindValue
untuk mengikatkan kolom dalam pengujian Anda ke grafik
dependensi Hilt dengan mudah. Anotasi kolom dengan @BindValue
dan kolomnya akan terikat dalam
jenis kolom yang dideklarasikan dengan penentu apa pun yang ada untuk kolom tersebut.
Dalam contoh AnalyticsService
, Anda dapat mengganti AnalyticsService
dengan
yang palsu menggunakan @BindValue
:
Kotlin
@UninstallModules(AnalyticsModule::class) @HiltAndroidTest class SettingsActivityTest { @BindValue @JvmField val analyticsService: AnalyticsService = FakeAnalyticsService() ... }
Java
@UninstallModules(AnalyticsModule.class) @HiltAndroidTest class SettingsActivityTest { @BindValue AnalyticsService analyticsService = FakeAnalyticsService(); ... }
Hal ini menyederhanakan penggantian binding dan perujukan binding dalam pengujian dengan memungkinkan Anda melakukan keduanya secara bersamaan.
@BindValue
berfungsi dengan penentu dan anotasi pengujian lainnya. Misalnya,
jika Anda menggunakan library pengujian seperti Mockito, Anda dapat menggunakannya dalam
uji Robolectric seperti berikut:
Kotlin
... class SettingsActivityTest { ... @BindValue @ExampleQualifier @Mock lateinit var qualifiedVariable: ExampleCustomType // Robolectric tests here }
Java
... class SettingsActivityTest { ... @BindValue @ExampleQualifier @Mock ExampleCustomType qualifiedVariable; // Robolectric tests here }
Jika perlu menambahkan multibinding,
Anda dapat menggunakan anotasi @BindValueIntoSet
dan @BindValueIntoMap
sebagai ganti
@BindValue
. @BindValueIntoMap
mewajibkan Anda untuk menganotasi juga kolom
dengan anotasi map key.
Kasus tertentu
Hilt juga menyediakan fitur untuk mendukung kasus penggunaan non-standar.
Aplikasi kustom untuk pengujian
Jika Anda tidak dapat menggunakan HiltTestApplication
karena aplikasi pengujian Anda perlu memperluas aplikasi lain, anotasilah class atau antarmuka baru dengan @CustomTestApplication
, sehingga meneruskan nilai class dasar yang Anda inginkan untuk diperluas oleh aplikasi Hilt yang dihasilkan.
@CustomTestApplication
akan menghasilkan class Application
yang siap diuji
dengan Hilt yang memperluas aplikasi yang Anda teruskan sebagai parameter.
Kotlin
@CustomTestApplication(BaseApplication::class) interface HiltTestApplication
Java
@CustomTestApplication(BaseApplication.class) interface HiltTestApplication { }
Dalam contoh ini, Hilt menghasilkan Application
bernama
HiltTestApplication_Application
yang memperluas class BaseApplication
. Secara umum, nama aplikasi yang dihasilkan adalah nama class yang dianotasi dan ditambahkan dengan _Application
. Anda harus menetapkan aplikasi
pengujian Hilt yang dihasilkan untuk dijalankan dalam uji instrumentasi atau uji Robolectric seperti yang dijelaskan dalam Aplikasi
pengujian.
Beberapa objek TestRule dalam uji instrumentasi
Jika Anda memiliki objek TestRule
lain dalam pengujian, ada beberapa cara untuk
memastikan bahwa semua aturan berfungsi bersama.
Anda dapat menggabungkan aturan sebagai berikut:
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. }
Atau, Anda dapat menggunakan kedua aturan di tingkat yang sama selama
HiltAndroidRule
dijalankan terlebih dahulu. Tentukan urutan eksekusi menggunakan
atribut order
dalam anotasi @Rule
. Ini hanya berfungsi di JUnit versi
4.13 atau yang lebih tinggi:
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
Penggunaan launchFragmentInContainer
dari
library androidx.fragment:fragment-testing
dengan Hilt tidak dapat dilakukan karena mengandalkan
aktivitas yang tidak dianotasi dengan @AndroidEntryPoint
.
Gunakan
kode launchFragmentInHiltContainer
dari
repositori GitHub
architecture-samples
.
Menggunakan titik entri sebelum komponen singleton tersedia
Anotasi @EarlyEntryPoint
menyediakan jalan keluar saat titik masuk
Hilt harus dibuat sebelum komponen singleton tersedia dalam
pengujian Hilt.
Informasi selengkapnya tentang @EarlyEntryPoint
ada dalam
dokumentasi Hilt.