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