من مزايا استخدام أُطر عمل لتوفير التبعية مثل 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") }
إعداد اختبار واجهة المستخدم
يجب إضافة التعليق التوضيحي @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 لجميع الاختبارات المبرمَجة في مشروعك. اتّبِع الخطوات التالية:
- أنشئ فئة مخصّصة تتضمّن
AndroidJUnitRunner
في المجلدandroidTest
. - تجاوز الدالة
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
بدلاً من ذلك، يمكنك ضبط إعدادات التطبيق في كل اختبار على حدة باستخدام التعليق التوضيحي @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. }
إذا كنت تستخدم إصدارًا من "إضافة Gradle لنظام التشغيل Android" أقل من 4.2، فعِّل تحويل فئات @AndroidEntryPoint
في اختبارات الوحدات المحلية من خلال تطبيق الإعداد التالي في ملف build.gradle
الخاص بالوحدة:
Groovy
hilt { enableTransformForLocalTests = true }
Kotlin
hilt { enableTransformForLocalTests = true }
يمكنك الاطّلاع على مزيد من المعلومات عن enableTransformForLocalTests
في مستندات Hilt.
ميزات الاختبار
بعد أن يصبح 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
في الاختبارات، أنشئ وحدة Hilt جديدة في المجلد test
أو androidTest
مع التبعية الوهمية وأضِف إليها التعليق التوضيحي @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 ); }
استبدال ربط في اختبار واحد
لاستبدال ربط في اختبار واحد بدلاً من جميع الاختبارات، عليك إلغاء تثبيت وحدة Hilt من اختبار باستخدام التعليق التوضيحي @UninstallModules
وإنشاء وحدة اختبار جديدة داخل الاختبار.
باتّباع مثال 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
من القسم أعلاه. بدلاً من ذلك، يمكنك وضع أداة ربط الاختبار في الوحدة test
لاختبارات Robolectric، أو في الوحدة androidTest
للاختبارات المبرمَجة.
ننصحك باستخدام @TestInstallIn
كلما أمكن ذلك.
ربط قيم جديدة
استخدِم التعليق التوضيحي @BindValue
لربط الحقول في اختبارك بسهولة بمخطط بيانات التبعية في Hilt. أضِف التعليق التوضيحي @BindValue
إلى حقل، وسيتم ربطه بنوع الحقل المعلَن عنه مع أي مؤهلات متوفّرة لهذا الحقل.
في مثال AnalyticsService
، يمكنك استبدال AnalyticsService
بنص مزيّف باستخدام @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(); ... }
يؤدي ذلك إلى تبسيط عملية استبدال رابط وعملية الإشارة إلى رابط في الاختبار من خلال السماح لك بإجراء كلتا العمليتين في الوقت نفسه.
تعمل السمة @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 }
إذا كنت بحاجة إلى إضافة ربط متعدّد، يمكنك استخدام التعليقين التوضيحيين @BindValueIntoSet
و@BindValueIntoMap
بدلاً من @BindValue
. يتطلّب @BindValueIntoMap
أيضًا إضافة تعليق توضيحي إلى الحقل
باستخدام تعليق توضيحي لمفتاح الخريطة.
حالات خاصة
توفّر Hilt أيضًا ميزات لدعم حالات الاستخدام غير العادية.
تطبيق مخصّص للاختبارات
إذا تعذّر عليك استخدام HiltTestApplication
لأنّ تطبيق الاختبار يحتاج إلى توسيع تطبيق آخر، يمكنك إضافة تعليق توضيحي إلى فئة أو واجهة جديدة باستخدام @CustomTestApplication
، مع تمرير قيمة الفئة الأساسية التي تريد أن يوسّعها تطبيق Hilt الذي تم إنشاؤه.
ستنشئ @CustomTestApplication
فئة Application
جاهزة للاختبار باستخدام Hilt، وتوسّع هذه الفئة التطبيق الذي تم تمريره كمَعلمة.
Kotlin
@CustomTestApplication(BaseApplication::class) interface HiltTestApplication
Java
@CustomTestApplication(BaseApplication.class) interface HiltTestApplication { }
في المثال، ينشئ Hilt فئة Application
باسم
HiltTestApplication_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
يتم تنفيذه أولاً. حدِّد ترتيب التنفيذ باستخدام السمة order
في التعليق التوضيحي @Rule
. لا تعمل هذه الميزة إلا في الإصدار 4.13 من JUnit أو الإصدارات الأحدث:
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
لا يمكن استخدام launchFragmentInContainer
من مكتبة androidx.fragment:fragment-testing
مع Hilt، لأنّها تعتمد على نشاط لم يتم وضع التعليق التوضيحي @AndroidEntryPoint
عليه.
يمكنك بدلاً من ذلك استخدام الرمز
launchFragmentInHiltContainer
من مستودع
architecture-samples
على GitHub.
استخدام نقطة دخول قبل توفّر المكوّن الفردي
تقدّم التعليق التوضيحي @EarlyEntryPoint
طريقة للحلّ عند الحاجة إلى إنشاء نقطة دخول في Hilt قبل أن يصبح المكوّن الفردي متاحًا في اختبار Hilt.
يمكنك الاطّلاع على مزيد من المعلومات حول @EarlyEntryPoint
في
مستندات Hilt.