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