تتمثل إحدى فوائد استخدام أطر عمل حقن التبعية مثل 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
في مشروعك:
رائع
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") }
إعداد اختبار واجهة المستخدم
يجب إضافة تعليقات توضيحية إلى أي اختبار لواجهة مستخدم يستخدم 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 في عنصر 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 كما هو موضَّح في دليل اختبار الوحدة للأجهزة. تأكد من استخدام مسار الفئة الكامل:
رائع
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. }
إذا كنت تستخدم إصدارًا أقدم من 4.2 من "مكوّن إضافي لنظام Gradle المتوافق مع Android"، يمكنك تفعيل خيار تحويل فئات @AndroidEntryPoint
في اختبارات الوحدات المحلية من خلال تطبيق الإعدادات التالية في ملف build.gradle
الخاص بالوحدة:
رائع
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. }
تشغيلFragmentInContainer
لا يمكن استخدام "launchFragmentInContainer
" من
مكتبة "androidx.fragment:fragment-testing
" مع Hilt، لأنّها تعتمد على
نشاط لم تتم إضافة تعليقات توضيحية إليه باستخدام @AndroidEntryPoint
.
استخدِم رمز launchFragmentInHiltContainer
من مستودع GitHub architecture-samples
بدلاً من ذلك.
استخدِم نقطة دخول قبل توفُّر مكوّن سينغلتون
يوفّر التعليق التوضيحي @EarlyEntryPoint
واجهة هروب عند الحاجة إلى إنشاء نقطة إدخال Hilt قبل توفّر مكوّن سينغلتون في اختبار Hilt.
يمكنك الاطّلاع على مزيد من المعلومات حول "@EarlyEntryPoint
" في
مستندات Hilt.