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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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.

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

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