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
डिपेंडेंसी शामिल करें:
ग्रूवी
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") }
यूज़र इंटरफ़ेस (यूआई) टेस्ट सेटअप करना
आपको @HiltAndroidTest
के साथ Hilt का इस्तेमाल करने वाले किसी भी यूज़र इंटरफ़ेस (यूआई) टेस्ट के लिए एनोटेट करना होगा. यह एनोटेशन, हर टेस्ट के लिए 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 के साथ काम करने वाले Application
ऑब्जेक्ट में, Hilt का इस्तेमाल करते हैं. टेस्ट में इस्तेमाल करने के लिए, लाइब्रेरी में 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 फ़ाइल में इस टेस्ट रनर को कॉन्फ़िगर करें. इसके लिए, इंस्ट्रुमेंट की गई यूनिट टेस्ट की गाइड में दिया गया तरीका अपनाएं. पक्का करें कि आपने पूरे क्लासपाथ का इस्तेमाल किया हो:
ग्रूवी
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 }
हिल्ट दस्तावेज़ में 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
उदाहरण के आधार पर, सबसे पहले Hilt को टेस्ट क्लास में @UninstallModules
एनोटेशन का इस्तेमाल करके, प्रोडक्शन मॉड्यूल को अनदेखा करने के लिए कहें:
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
का इस्तेमाल करें.
नई वैल्यू बांधना
अपने टेस्ट में मौजूद फ़ील्ड को Hilt डिपेंडेंसी ग्राफ़ में आसानी से बांधने के लिए, @BindValue
एनोटेशन का इस्तेमाल करें. किसी फ़ील्ड को @BindValue
के साथ एनोटेट करें. इससे वह फ़ील्ड, एनोटेट किए गए फ़ील्ड टाइप के तहत, उस फ़ील्ड के लिए मौजूद सभी क्वालिफ़ायर के साथ बाउंड हो जाएगा.
AnalyticsService
के उदाहरण में, @BindValue
का इस्तेमाल करके AnalyticsService
को नकली वैल्यू से बदला जा सकता है:
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 HiltTestApplication_Application
नाम का एक Application
जनरेट करता है. यह BaseApplication
क्लास को बढ़ाता है. आम तौर पर, जनरेट किए गए ऐप्लिकेशन का नाम, _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 एंट्री पॉइंट बनाने के लिए एक 'इस्केप हैच' उपलब्ध कराता है.
हिल्ट दस्तावेज़ में @EarlyEntryPoint
के बारे में ज़्यादा जानकारी देखें.