تتمثل إحدى فوائد استخدام أطر حقن التبعية مثل 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.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") }
الإعداد التجريبي لواجهة المستخدم
يجب إضافة تعليقات توضيحية إلى أي اختبار واجهة مستخدم يستخدِم 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
لربط الحقول في اختبارك بسهولة في مخطّط @BindValue
التسلسل الهرمي للتبعيات في Hilt. أضِف تعليقات توضيحية إلى حقل @BindValue
وسيتم ربطه ضمن نوع الحقل المعلَن عنه بأي مؤهِّلات متوفّرة لهذا الحقل.
في مثال AnalyticsService
، يمكنك استبدال AnalyticsService
بعبارة
fake باستخدام @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
من مستودع GitHub
architecture-samples
بدلاً من ذلك.
استخدام نقطة دخول قبل أن يصبح المكوِّن المفردتون متاحًا
يقدّم التعليق التوضيحي @EarlyEntryPoint
مخرجًا عند الحاجة إلى إنشاء نقطة دخول
Hilt قبل توفّر المكوّن الفردي في اختبار
Hilt.
يمكنك الاطّلاع على مزيد من المعلومات عن @EarlyEntryPoint
في
مستندات Hilt.