استخدام اختبار الضعف في Android

عند اختبار عنصر أو نظام من العناصر، يتم ذلك بشكل منفصل. على سبيل المثال، لاختبار ViewModel، لا تحتاج إلى بدء محاكي وتشغيل واجهة مستخدِم لأنّ ذلك لا يعتمد (أو لا ينبغي) على إطار عمل Android.

ومع ذلك، قد يعتمد الموضوع الذي يتم اختباره على عوامل أخرى لكي يعمل. على سبيل المثال، قد يعتمد ViewModel على مستودع بيانات لكي يعمل.

عندما تحتاج إلى توفير عنصر تابع لموضوع قيد الاختبار، من الشائع إنشاء عنصر اختبار مزدوج (أو عنصر اختبار). العناصر المزدوجة للاختبار هي عناصر تبدو وكأنها مكوّنات في تطبيقك وتؤدي وظائفها، ولكن يتم إنشاؤها في الاختبار لتوفير سلوك أو بيانات معيّنة. وتتمثل المزايا الرئيسية في أنّها تجعل اختباراتك أسرع وأسهل.

أنواع النماذج المزدوجة للاختبار

هناك أنواع مختلفة من النماذج المزدوجة للاختبار:

مورِّد مزيف عنصر اختبار مزدوج يتضمّن تنفيذًا "صالحًا" للفئة، ولكن يتم تنفيذه بطريقة تجعله مناسبًا للاختبارات ولكن غير مناسب للإصدار العلني.

مثال: قاعدة بيانات في الذاكرة.

لا تتطلّب النماذج المزيّفة إطار عملًا للاختبار وتكون خفيفة الوزن. وهي مفضّلة.

محاكاة عنصر اختبار بديل يتصرف بالطريقة التي تبرمجه بها ويتوقع تفاعلات معيّنة لن تجتاز هذه النماذج الاختبارات إذا لم تتوافق تفاعلاتها مع المتطلبات التي تحدّدها. يتم عادةً إنشاء النماذج باستخدام إطار عمل محاكاة لتحقيق كل ذلك.

مثال: التأكّد من أنّه تم استدعاء طريقة في قاعدة بيانات مرة واحدة بالضبط

Stub اختبار مزدوج يتصرف كيفية برمجته ليعمل ولكن ليس له توقعات حول تفاعلاته. يتم إنشاؤها عادةً باستخدام إطار عمل محاكاة. يُفضّل استخدام النماذج المزيّفة بدلاً من النماذج النموذجية من أجل البساطة.
Dummy عنصر اختبار مزدوج يتم تمريره ولكن لا يتم استخدامه، مثل إذا كنت بحاجة إلى تقديمه كمَعلمة فقط.

مثال: تم تمرير دالة فارغة كرد اتصال للنقرة.

الجاسوسية عنصر لفّ حول عنصر حقيقي يتتبّع أيضًا بعض المعلومات الإضافية، مثل النماذج الاختبارية ويتم تجنُّبها عادةً بسبب إضافة تعقيد. لذلك، يُفضّل استخدام النماذج المزيّفة أو النماذج الاختبارية بدلاً من النماذج التجسّسية.
ظل تم استخدام Fake في Robolectric.

مثال على استخدام بيانات مزيفة

لنفترض أنّك تريد إجراء اختبار وحدة لـ ViewModel يعتمد على واجهة تُسمى UserRepository ويعرِض اسم المستخدم الأول لواجهة مستخدم. يمكنك إنشاء اختبار مزيّف مرتين من خلال تنفيذ الواجهة وعرض بيانات معروفة.

object FakeUserRepository : UserRepository {
    fun getUsers() = listOf(UserAlice, UserBob)
}

val const UserAlice = User("Alice")
val const UserBob = User("Bob")

ولا يحتاج هذا الإصدار الاصطناعي من UserRepository إلى الاعتماد على مصادر البيانات المحلية والبعيدة التي سيستخدمها الإصدار العلني. يوجد الملف في مجموعة مصادر الاختبار ولن يتم شحنه مع تطبيق الإنتاج.

يمكن أن يعرض العنصر التابع المزيّف بيانات معروفة بدون الاعتماد على مصادر بيانات عن بُعد.
الشكل 1: تبعية زائفة في اختبار الوحدة

يُجري الاختبار التالي عملية تحقّق من أنّ ViewModel يعرِض بشكلٍ صحيح اسم المستخدم الأول للعرض.

@Test
fun viewModelA_loadsUsers_showsFirstUser() {
    // Given a VM using fake data
    val viewModel = ViewModelA(FakeUserRepository) // Kicks off data load on init

    // Verify that the exposed data is correct
    assertEquals(viewModel.firstUserName, UserAlice.name)
}

من السهل استبدال UserRepository بعنصر مزيّف في اختبار الوحدة، لأنّ المختبِر هو من ينشئ UserRepository. ومع ذلك، قد يكون من الصعب استبدال العناصر العشوائية في الاختبارات الأكبر حجمًا.

استبدال المكوّنات وحقن التبعيات

عندما لا تتحكّم الاختبارات في إنشاء الأنظمة التي يتم اختبارها، يصبح استبدال المكوّنات بعناصر اختبارية مزدوجة أكثر تعقيدًا ويتطلّب أن تتّبع بنية تطبيقك تصميمًا قابلاً للاختبار.

حتى الاختبارات الشاملة الكبيرة يمكن أن تستفيد من استخدام الاختبارات المزدوجة التجريبية، مثل اختبار واجهة مستخدم قياسي يتنقل عبر تدفق المستخدم الكامل في التطبيق. في هذه الحالة، قد تحتاج إلى جعل الاختبار مرصودًا. يتجنّب الاختبار التام جميع التبعيات الخارجية، مثل جلب البيانات من الإنترنت. ويؤدي ذلك إلى تحسين الموثوقية والأداء.

الشكل 2: اختبار كبير يغطي معظم أجزاء التطبيق ويُنشئ بيانات زائفة عن بُعد

يمكنك تصميم تطبيقك لتحقيق هذه المرونة يدويًا، ولكننا ننصحك باستخدام إطار عمل إدخال الاعتماد مثل Hilt لاستبدال المكوّنات في تطبيقك في وقت الاختبار. اطّلِع على دليل اختبار Hilt.

الخطوات التالية

توضّح صفحة استراتيجيات الاختبار كيفية تحسين إنتاجيتك باستخدام أنواع مختلفة من الاختبارات.