Hilt जैसे डिपेंडेंसी इंजेक्शन फ़्रेमवर्क का इस्तेमाल करने का एक फ़ायदा यह है कि इससे आपके कोड की जांच करना आसान हो जाता है.
यूनिट टेस्ट
यूनिट टेस्ट के लिए Hilt का इस्तेमाल करना ज़रूरी नहीं है. ऐसा इसलिए, क्योंकि कंस्ट्रक्टर इंजेक्शन का इस्तेमाल करने वाली क्लास को टेस्ट करते समय, आपको उस क्लास को इंस्टैंटिएट करने के लिए Hilt का इस्तेमाल करने की ज़रूरत नहीं होती. इसके बजाय, फ़र्ज़ी या मॉक डिपेंडेंसी पास करके, सीधे तौर पर किसी क्लास कंस्ट्रक्टर को कॉल किया जा सकता है. ठीक उसी तरह जैसे कंस्ट्रक्टर को एनोटेट नहीं किया गया है:
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(...); } }
एंड-टू-एंड टेस्ट
इंटिग्रेशन टेस्ट के लिए, Hilt डिपेंडेंसी को उसी तरह इंजेक्ट करता है जिस तरह वह आपके प्रोडक्शन कोड में करता है. Hilt के साथ टेस्टिंग करने के लिए, किसी रखरखाव की ज़रूरत नहीं होती. ऐसा इसलिए, क्योंकि Hilt हर टेस्ट के लिए कॉम्पोनेंट का नया सेट अपने-आप जनरेट करता है.
टेस्टिंग डिपेंडेंसी जोड़ना
अपने टेस्ट में Hilt का इस्तेमाल करने के लिए, अपने प्रोजेक्ट में hilt-android-testing
डिपेंडेंसी शामिल करें:
Groovy
dependencies { // For Robolectric tests. testImplementation 'com.google.dagger:hilt-android-testing:2.56.2' // ...with Kotlin. kaptTest 'com.google.dagger:hilt-android-compiler:2.56.2' // ...with Java. testAnnotationProcessor 'com.google.dagger:hilt-android-compiler:2.56.2' // For instrumented tests. androidTestImplementation 'com.google.dagger:hilt-android-testing:2.56.2' // ...with Kotlin. kaptAndroidTest 'com.google.dagger:hilt-android-compiler:2.56.2' // ...with Java. androidTestAnnotationProcessor 'com.google.dagger:hilt-android-compiler:2.56.2' }
Kotlin
dependencies { // For Robolectric tests. testImplementation("com.google.dagger:hilt-android-testing:2.56.2") // ...with Kotlin. kaptTest("com.google.dagger:hilt-android-compiler:2.56.2") // ...with Java. testAnnotationProcessor("com.google.dagger:hilt-android-compiler:2.56.2") // For instrumented tests. androidTestImplementation("com.google.dagger:hilt-android-testing:2.56.2") // ...with Kotlin. kaptAndroidTest("com.google.dagger:hilt-android-compiler:2.56.2") // ...with Java. androidTestAnnotationProcessor("com.google.dagger:hilt-android-compiler:2.56.2") }
यूज़र इंटरफ़ेस (यूआई) टेस्ट सेटअप करना
Hilt का इस्तेमाल करने वाले हर यूज़र इंटरफ़ेस (यूआई) टेस्ट को @HiltAndroidTest
से एनोटेट करना ज़रूरी है. यह एनोटेशन, हर टेस्ट के लिए Hilt कॉम्पोनेंट जनरेट करता है.
साथ ही, आपको टेस्ट क्लास में HiltAndroidRule
जोड़ना होगा. यह कॉम्पोनेंट की स्थिति को मैनेज करता है. इसका इस्तेमाल आपके टेस्ट में इंजेक्शन करने के लिए किया जाता है:
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. }
इसके बाद, आपके टेस्ट को Application
क्लास के बारे में पता होना चाहिए. यह क्लास, Hilt आपके लिए अपने-आप जनरेट करता है.
टेस्ट ऐप्लिकेशन
आपको ऐसे इंस्ट्रुमेंटेड टेस्ट चलाने होंगे जिनमें Hilt का इस्तेमाल किया जाता है. ये टेस्ट, Hilt के साथ काम करने वाले Application
ऑब्जेक्ट में चलाए जाने चाहिए. यह लाइब्रेरी, टेस्ट में इस्तेमाल करने के लिए HiltTestApplication
उपलब्ध कराती है.
अगर आपके टेस्ट के लिए किसी दूसरे ऐप्लिकेशन की ज़रूरत है, तो टेस्ट के लिए कस्टम ऐप्लिकेशन लेख पढ़ें.
आपको अपने टेस्ट ऐप्लिकेशन को इंस्ट्रुमेंटेड टेस्ट या Robolectric टेस्ट में चलाने के लिए सेट करना होगा. यहां दिए गए निर्देश, खास तौर पर Hilt के लिए नहीं हैं. हालांकि, ये टेस्ट में चलाने के लिए कस्टम ऐप्लिकेशन तय करने के बारे में सामान्य दिशा-निर्देश हैं.
इंस्ट्रुमेंट किए गए टेस्ट में टेस्ट ऐप्लिकेशन सेट करना
इंस्ट्रुमेंट किए गए टेस्ट में Hilt टेस्ट ऐप्लिकेशन का इस्तेमाल करने के लिए, आपको नया टेस्ट रनर कॉन्फ़िगर करना होगा. इससे, आपके प्रोजेक्ट में इंस्ट्रुमेंट किए गए सभी टेस्ट के लिए Hilt काम करता है. यह तरीका अपनाएं:
androidTest
फ़ोल्डर मेंAndroidJUnitRunner
को बढ़ाने वाली कोई कस्टम क्लास बनाएं.newApplication
फ़ंक्शन को बदलें और जनरेट किए गए Hilt टेस्ट ऐप्लिकेशन का नाम पास करें.
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); } }
इसके बाद, इस टेस्ट रनर को अपनी Gradle फ़ाइल में कॉन्फ़िगर करें. इसके लिए, इंस्ट्रुमेंटेड यूनिट टेस्ट गाइड में दिया गया तरीका अपनाएं. पक्का करें कि आपने पूरा क्लासपाथ इस्तेमाल किया हो:
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 टेस्ट में टेस्ट ऐप्लिकेशन सेट करना
अगर यूज़र इंटरफ़ेस (यूआई) लेयर की जांच करने के लिए Robolectric का इस्तेमाल किया जाता है, तो robolectric.properties
फ़ाइल में यह तय किया जा सकता है कि किस ऐप्लिकेशन का इस्तेमाल करना है:
application = dagger.hilt.android.testing.HiltTestApplication
इसके अलावा, Robolectric के @Config
एनोटेशन का इस्तेमाल करके, हर टेस्ट के लिए ऐप्लिकेशन को अलग-अलग कॉन्फ़िगर किया जा सकता है:
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 प्लग इन का वर्शन 4.2 से कम है, तो लोकल यूनिट टेस्ट में @AndroidEntryPoint
क्लास को बदलने की सुविधा चालू करें. इसके लिए, अपने मॉड्यूल की build.gradle
फ़ाइल में यह कॉन्फ़िगरेशन लागू करें:
Groovy
hilt { enableTransformForLocalTests = true }
Kotlin
hilt { enableTransformForLocalTests = true }
Hilt के दस्तावेज़ में enableTransformForLocalTests
के बारे में ज़्यादा जानकारी.
टेस्टिंग की सुविधाएं
टेस्ट में Hilt का इस्तेमाल करने के लिए तैयार हो जाने के बाद, टेस्टिंग की प्रोसेस को अपनी पसंद के मुताबिक बनाने के लिए कई सुविधाओं का इस्तेमाल किया जा सकता है.
जांच में टाइप इंजेक्ट करना
किसी टेस्ट में टाइप इंजेक्ट करने के लिए, फ़ील्ड इंजेक्शन के लिए @Inject
का इस्तेमाल करें. Hilt को @Inject
फ़ील्ड भरने के लिए, hiltRule.inject()
को कॉल करें.
इंस्ट्रुमेंट किए गए टेस्ट का यह उदाहरण देखें:
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. } }
बाइंडिंग बदलना
अगर आपको किसी डिपेंडेंसी का फ़र्ज़ी या मॉक इंस्टेंस इंजेक्ट करना है, तो आपको Hilt को यह बताना होगा कि वह प्रोडक्शन कोड में इस्तेमाल किए गए बाइंडिंग का इस्तेमाल न करे और इसके बजाय किसी दूसरे बाइंडिंग का इस्तेमाल करे. किसी बाइंडिंग को बदलने के लिए, आपको उस मॉड्यूल को बदलना होगा जिसमें बाइंडिंग है. इसके लिए, आपको एक ऐसा टेस्ट मॉड्यूल इस्तेमाल करना होगा जिसमें वे बाइंडिंग हों जिनका इस्तेमाल आपको टेस्ट में करना है.
उदाहरण के लिए, मान लें कि आपका प्रोडक्शन कोड, AnalyticsService
के लिए बाइंडिंग इस तरह से दिखाता है:
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 ); }
जांचों में AnalyticsService
बाइंडिंग को बदलने के लिए, test
या androidTest
फ़ोल्डर में एक नया Hilt मॉड्यूल बनाएं. इसमें नकली डिपेंडेंसी शामिल करें और इसे @TestInstallIn
के साथ एनोटेट करें. उस फ़ोल्डर में मौजूद सभी टेस्ट में, फ़र्ज़ी डिपेंडेंसी डाली जाती है.
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 ); }
किसी एक टेस्ट में बाइंडिंग बदलना
सभी टेस्ट के बजाय किसी एक टेस्ट में बाइंडिंग को बदलने के लिए, @UninstallModules
एनोटेशन का इस्तेमाल करके, टेस्ट से Hilt मॉड्यूल अनइंस्टॉल करें. इसके बाद, टेस्ट के अंदर एक नया टेस्ट मॉड्यूल बनाएं.
पिछले वर्शन के AnalyticsService
उदाहरण के मुताबिक, टेस्ट क्लास में @UninstallModules
एनोटेशन का इस्तेमाल करके, Hilt को प्रोडक्शन मॉड्यूल को अनदेखा करने के लिए कहें:
Kotlin
@UninstallModules(AnalyticsModule::class) @HiltAndroidTest class SettingsActivityTest { ... }
Java
@UninstallModules(AnalyticsModule.class) @HiltAndroidTest public final class SettingsActivityTest { ... }
इसके बाद, आपको बाइंडिंग बदलनी होगी. टेस्ट क्लास में एक नया मॉड्यूल बनाएं. यह मॉड्यूल, टेस्ट बाइंडिंग को तय करता है:
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 ); } ... }
इससे सिर्फ़ एक टेस्ट क्लास के लिए बाइंडिंग बदलती है. अगर आपको सभी टेस्ट क्लास के लिए बाइंडिंग बदलनी है, तो ऊपर दिए गए सेक्शन में मौजूद @TestInstallIn
एनोटेशन का इस्तेमाल करें. इसके अलावा, टेस्ट बाइंडिंग को Robolectric टेस्ट के लिए test
मॉड्यूल में या इंस्ट्रुमेंटेड टेस्ट के लिए androidTest
मॉड्यूल में रखा जा सकता है.
हमारा सुझाव है कि जब भी हो सके, @TestInstallIn
का इस्तेमाल करें.
नई वैल्यू बाइंड करना
@BindValue
एनोटेशन का इस्तेमाल करके, अपने टेस्ट के फ़ील्ड को Hilt डिपेंडेंसी ग्राफ़ में आसानी से बाइंड करें. किसी फ़ील्ड को @BindValue
के साथ एनोटेट करें. इसके बाद, उसे घोषित किए गए फ़ील्ड टाइप के तहत बाइंड कर दिया जाएगा. साथ ही, उस फ़ील्ड के लिए मौजूद किसी भी क्वालिफ़ायर को भी बाइंड कर दिया जाएगा.
AnalyticsService
उदाहरण में, @BindValue
का इस्तेमाल करके, AnalyticsService
को a
fake से बदला जा सकता है:
Kotlin
@UninstallModules(AnalyticsModule::class) @HiltAndroidTest class SettingsActivityTest { @BindValue @JvmField val analyticsService: AnalyticsService = FakeAnalyticsService() ... }
Java
@UninstallModules(AnalyticsModule.class) @HiltAndroidTest class SettingsActivityTest { @BindValue AnalyticsService analyticsService = FakeAnalyticsService(); ... }
इससे, टेस्ट में बाइंडिंग को बदलना और बाइंडिंग को रेफ़रंस करना आसान हो जाता है. ऐसा इसलिए, क्योंकि इन दोनों को एक साथ किया जा सकता है.
@BindValue
, क्वालिफ़ायर और टेस्टिंग से जुड़ी अन्य एनोटेशन के साथ काम करता है. उदाहरण के लिए, अगर Mockito जैसी टेस्टिंग लाइब्रेरी का इस्तेमाल किया जाता है, तो उसे Robolectric टेस्ट में इस तरह इस्तेमाल किया जा सकता है:
Kotlin
... class SettingsActivityTest { ... @BindValue @ExampleQualifier @Mock lateinit var qualifiedVariable: ExampleCustomType // Robolectric tests here }
Java
... class SettingsActivityTest { ... @BindValue @ExampleQualifier @Mock ExampleCustomType qualifiedVariable; // Robolectric tests here }
अगर आपको मल्टीबाइंडिंग जोड़नी है, तो @BindValue
की जगह @BindValueIntoSet
और @BindValueIntoMap
एनोटेशन का इस्तेमाल किया जा सकता है. @BindValueIntoMap
के लिए, आपको मैप कुंजी के एनोटेशन के साथ फ़ील्ड को एनोटेट करना होगा.
विशेष मामले
Hilt, इस्तेमाल के गैर-स्टैंडर्ड उदाहरणों के लिए भी सुविधाएं उपलब्ध कराता है.
टेस्ट के लिए कस्टम ऐप्लिकेशन
अगर आपको HiltTestApplication
का इस्तेमाल करने में समस्या आ रही है, क्योंकि आपके टेस्ट ऐप्लिकेशन को किसी दूसरे ऐप्लिकेशन को एक्सटेंड करने की ज़रूरत है, तो @CustomTestApplication
के साथ नई क्लास या इंटरफ़ेस एनोटेट करें. साथ ही, उस बेस क्लास की वैल्यू पास करें जिसे आपको जनरेट किए गए Hilt ऐप्लिकेशन को एक्सटेंड करना है.
@CustomTestApplication
, Hilt के साथ टेस्ट करने के लिए तैयार Application
क्लास जनरेट करेगा. यह उस ऐप्लिकेशन को बढ़ाता है जिसे आपने पैरामीटर के तौर पर पास किया है.
Kotlin
@CustomTestApplication(BaseApplication::class) interface HiltTestApplication
Java
@CustomTestApplication(BaseApplication.class) interface HiltTestApplication { }
इस उदाहरण में, Hilt BaseApplication
क्लास को बढ़ाने वाला Application
नाम का HiltTestApplication_Application
जनरेट करता है. आम तौर पर, जनरेट किए गए ऐप्लिकेशन का नाम, एनोटेट की गई क्लास का नाम होता है. इसके आखिर में _Application
जोड़ा जाता है. आपको जनरेट किए गए Hilt टेस्ट ऐप्लिकेशन को इंस्ट्रुमेंट किए गए टेस्ट या Robolectric टेस्ट में चलाना होगा. इसके बारे में टेस्ट ऐप्लिकेशन में बताया गया है.
आपके इंस्ट्रुमेंटेड टेस्ट में एक से ज़्यादा TestRule ऑब्जेक्ट
अगर आपके टेस्ट में अन्य TestRule
ऑब्जेक्ट हैं, तो यह पक्का करने के कई तरीके हैं कि सभी नियम एक साथ काम करें.
नियमों को इस तरह से एक साथ रैप किया जा सकता है:
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. }
इसके अलावा, दोनों नियमों का इस्तेमाल एक ही लेवल पर किया जा सकता है. हालांकि, ऐसा तब ही किया जा सकता है, जब HiltAndroidRule
पहले लागू हो. @Rule
एनोटेशन में order
एट्रिब्यूट का इस्तेमाल करके, लागू होने का क्रम तय करें. यह सिर्फ़ JUnit 4.13 या इसके बाद के वर्शन में काम करता है:
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 के साथ androidx.fragment:fragment-testing
लाइब्रेरी से launchFragmentInContainer
का इस्तेमाल नहीं किया जा सकता, क्योंकि यह ऐसी गतिविधि पर निर्भर करता है जिसे @AndroidEntryPoint
के साथ एनोटेट नहीं किया गया है.
इसके बजाय, architecture-samples
GitHub रिपॉज़िटरी से launchFragmentInHiltContainer
कोड का इस्तेमाल करें.
सिंगलटन कॉम्पोनेंट के उपलब्ध होने से पहले किसी एंट्री पॉइंट का इस्तेमाल करना
@EarlyEntryPoint
एनोटेशन, तब काम आता है, जब Hilt टेस्ट में सिंगलटन कॉम्पोनेंट उपलब्ध होने से पहले, Hilt एंट्री पॉइंट बनाना होता है.
Hilt के दस्तावेज़ में, @EarlyEntryPoint
के बारे में ज़्यादा जानकारी.