Robolectric — ما هو، مبادئ العمل واختبارات الوحدة لأندرويد

المؤلف: IT Sectr نُشر: 2026-04-09 وقت القراءة: 8 دق

Robolectric هو إطار عمل لاختبارات الوحدة لتطبيقات أندرويد يتيح تشغيل الاختبارات مباشرة على JVM دون محاكي أو جهاز فعلي. يعترض استدعاءات Android SDK ويوفر كائنات ظل (shadow-objects) تحاكي سلوك المكونات الحقيقية. وفقاً لـ Robolectric Documentation, 2025، تستبدل كائنات الظل حوالي 15 ألف فئة من Android API، مما يضمن عزل الاختبارات عن المنصة.

الرئيسي

  • Robolectric — إطار عمل لاختبارات الوحدة لأندرويد دون محاكي، يعمل على JVM
  • كائنات الظل تعترض استدعاءات Android SDK وتحاكي سلوك النظام
  • التكامل مع JUnit 4 و5 يسمح باستخدام مشغّلات الاختبارات القياسية
  • الاختبارات تُنفذ في ثوانٍ وليس دقائق كما في المحاكي
  • الدعم لـ Jetpack Compose والأجزاء (fragments) والنوايا (intents) و ContentProvider والموارد

ما هو Robolectric

Robolectric هو إطار عمل مفتوح المصدر أُنشئ في 2010 لتسريع اختبار تطبيقات أندرويد. بدلاً من التشغيل على محاكي أو جهاز، يوفر Robolectric تطبيقات ظل لفئات Android SDK تعمل مباشرة على الآلة الافتراضية لجافا (JVM). هذا يسمح بتنفيذ آلاف الاختبارات في ثوانٍ.

المشكلة التي يحلها Robolectric

يتطلب اختبار أندرويد التقليدي تشغيل التطبيق على محاكي، مما يستغرق 3–10 دقائق لبناء APK وتثبيته وتشغيله. يلغي Robolectric هذه الخطوة: تُجمّع الاختبارات كاختبارات Java/Kotlin عادية وتُشغّل عبر JUnit. هذا يوفر دورة استجابة في ثوانٍ بدلاً من دقائق.

إصدارات أندرويد المدعومة

يدعم Robolectric جميع إصدارات أندرويد بدءاً من API 16 (Android 4.1) وحتى أحدث إصدار مستقر. لكل إصدار يتم توفير مجموعة مقابلة من كائنات الظل التي تحاكي سلوك إصدار المنصة الذي يُختبر عليه التطبيق.

الهندسة المعمارية وكائنات الظل

تعتمد بنية Robolectric على اعتراض الاستدعاءات من خلال استبدال محمّل الفئات (classloader). عندما يستدعي اختبار طريقة من Android SDK، يعترض Robolectric الاستدعاء ويوجّهه إلى كائن ظل. كائن الظل هو فئة Java تحاكي السلوك الحقيقي لمكون Android ولكنها تعمل دون المنصة الأصلية.

كيف تعمل الظلال

تنفّذ كائنات الظل الطرق الرئيسية لفئات Android الأصلية. على سبيل المثال، يحاكي ShadowTextView طرقاً مثل getText() و setText() و getCurrentTextColor() وغيرها. عند استدعاء textView.setText("مرحباً")، يحفظ الظل السلسلة ويعيدها عند استدعاء getText(). هذا يعزل الاختبارات عن العرض الحقيقي وخدمات النظام.

التسلسل الهرمي للظلال

يدعم Robolectric أكثر من 200 فئة ظل تغطي المكونات الرئيسية لـ Android SDK: Activity و Fragment و TextView و Button و RecyclerView و WebView و LocationManager و ConnectivityManager وغيرها الكثير. تتبع كائنات الظل نفس التسلسل الهرمي للوراثة مثل فئات Android الأصلية.

تثبيت وإعداد Robolectric

يتطلب تثبيت Robolectric في مشروع Gradle إضافة التبعية testImplementation "org.robolectric:robolectric:4.x". من الضروري أيضاً تحديد إعداد androidsdk في ملف build.gradle وإضافة إذن android:testInstrumentationRunner. لا حاجة لإضافة إضافة اختبارات Android للعمل مع Robolectric.

إعداد Gradle الأساسي

بعد إضافة التبعية، يجب تكوين الدليل الخاص بالمانيفست والموارد والأصول. يجد Robolectric تلقائياً AndroidManifest.xml، ولكن قد تحتاج إلى تحديد المسار يدوياً عبر تعليمة @Config أو خصائص النظام. للمشاريع متعددة الوحدات، يُحدد الإعداد بشكل منفصل لكل وحدة.

groovy
// build.gradle — إعداد Robolectric
android {
    testOptions {
        unitTests.includeAndroidResources = true
        unitTests.all {
            systemProperty 'robolectric.dependency.dir',
                project.rootDir.absolutePath + '/build/intermediates'
        }
    }
}

dependencies {
    testImplementation 'org.robolectric:robolectric:4.13'
    testImplementation 'org.junit.jupiter:junit-jupiter:5.10.0'
}

تعليمة @Config

تسمح تعليمة @Config بتجاوز معلمات الاختبار: sdk (إصدار API)، manifest (المسار إلى المانيفست)، qualifiers (تكوين الشاشة، اللغة). هذا مفيد لاختبار سلوك التطبيق على إصدارات مختلفة من أندرويد واتجاهات الشاشة والإعدادات المحلية.

كتابة الاختبارات مع Robolectric

تُكتب اختبارات Robolectric كاختبارات وحدة عادية باستخدام @RunWith(RobolectricTestRunner.class) لـ JUnit 4 أو عبر RobolectricExtension لـ JUnit 5. ActivityController يدير دورة حياة Activity: create() و start() و resume() و pause() و stop() و destroy(). هذا يسمح باختبار كل انتقال حالة بالتفصيل.

اختبار Activity

لاختبار Activity يُستخدم ActivityController الذي يمر بالتسلسل عبر مراحل دورة الحياة. الوصول إلى Activity يتم عبر controller.get(). جميع مكونات العرض متاحة عبر findViewById كما في التطبيق الحقيقي. تسمح كائنات الظل بالتحقق من النصوص والرؤية والألوان وخصائص العرض الأخرى.

java
@RunWith(RobolectricTestRunner.class)
@Config(sdk = BuildConfig.SDK_INT)
public class MainActivityTest {

    @Test
    public void testActivityDisplaysGreeting() {
        ActivityController<MainActivity> controller =
            Robolectric.buildActivity(MainActivity.class);
        controller.create().start().resume();

        MainActivity activity = controller.get();
        TextView greeting = activity.findViewById(R.id.greeting);
        ShadowTextView shadow = Shadows.shadowOf(greeting);

        assertEquals("Welcome!", shadow.getText());
    }
}

اختبار النوايا والتنقل

يعترض Robolectric استدعاءات startActivity() ويسمح بالتحقق من النوايا المرسلة عبر ShadowActivity. هذا يتيح اختبار التنقل: التحقق من أن الضغط على زر يرسل Intent مع Action و Data ومعاملات Extra صحيحة.

java
@Test
public void testNavigationToDetails() {
    controller.create().start().resume();
    MainActivity activity = controller.get();

    activity.findViewById(R.id.detailsButton).performClick();

    ShadowActivity shadowActivity = Shadows.shadowOf(activity);
    Intent intent = shadowActivity.getNextStartedActivity();
    assertEquals(
        DetailsActivity.class.getName(),
        intent.getComponent().getClassName()
    );
}

Robolectric مقابل المحاكي

يحل Robolectric والمحاكي مهامّاً مختلفة. Robolectric مثالي لـ اختبارات الوحدة السريعة والتحقق من منطق واجهة المستخدم ومكونات الأعمال والمستودعات. المحاكي ضروري لاختبارات الأدوات والتحقق من التكامل مع API واختبار الكاميرا وأجهزة الاستشعار والأداء.

الخاصيةRobolectricالمحاكي
السرعة~5 ثوانٍ لكل 100 اختبار~5 دقائق لكل 100 اختبار
التشغيلبدون بناء APKيتطلب بناء APK
API حقيقيمحاكاة ظلAndroid SDK أصلي
جاهز للاستخدامJUnit فقطأي أطر عمل

اختبار ViewModel و Repository

Robolectric مناسب تماماً لاختبار ViewModel و Repository و UseCase — المكونات التي تستخدم Android SDK ولكنها لا تتطلب واجهة مستخدم حقيقية. ViewModel يُختبر عبر اختبار JUnit عادي مع RobolectricExtension، بينما تعمل مكونات دورة الحياة (LiveData, StateFlow) في بيئة الظل دون نماذج وهمية (mocks).

اختبار LiveData

يدعم Robolectric LiveData بشكل مباشر: يمكنك الاشتراك في LiveData في الاختبار، وتغيير الحالة عبر ViewModel والتحقق من القيمة المُرسلة. للعمليات غير المتزامنة يُستخدم InstantTaskExecutorRule أو runBlocking للكوروتينات. هذا يلغي الحاجة إلى محاكاة المكونات المعمارية.

kotlin
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [BuildConfig.SDK_INT])
class ProfileViewModelTest {

    private val repository = FakeUserRepository()
    private val viewModel = ProfileViewModel(repository)

    @Test
    fun `loading profile sets state to success`() = runBlocking {
        viewModel.loadProfile("user123")
        val state = viewModel.profileState.getOrAwaitValue()
        Assertions.assertTrue(state is UiState.Success)
    }
}

كائنات ظل مخصصة

إذا كانت كائنات الظل القياسية لـ Robolectric لا تغطي فئة Android SDK المطلوبة، يمكنك إنشاء ظل مخصص. للقيام بذلك، أنشئ فئة بتعليمة @Implements(ClassName.class) ونفّذ الطرق المطلوبة باستخدام @Implementation. تُسجّل الظلال المخصصة عبر @Config(shadows = [CustomShadow::class]).

اختبار ContentProvider والموارد

يدعم Robolectric اختبار ContentProvider عبر Robolectric.buildContentProvider(). يمكنك التحقق من عمليات CRUD والاستعلامات بمطابقة URI ومعالجة أذونات الوصول. الموارد (النصوص والألوان والأبعاد) متاحة أيضاً عبر RuntimeEnvironment.application.resources، مما يسمح باختبار الكود الذي يعتمد على الموارد.

الانتقال من المحاكي إلى Robolectric

يتطلب الانتقال من اختبارات الأدوات إلى Robolectric تغيير النهج. اختبارات الأدوات (AndroidJUnit4) تتحقق من السلوك الحقيقي على المحاكي، بينما يتحقق Robolectric من المنطق المعزول في بيئة ظل. يُوصى بتغطية منطق الأعمال باختبارات Robolectric وترك اختبارات الأدوات لسيناريوهات التكامل.

تكييف الاختبارات الحالية

عند الانتقال، يجب: استبدال AndroidJUnit4 بـ RobolectricTestRunner، إضافة @Config مع إصدار SDK المستهدف، استبدال ActivityTestRule بـ ActivityController، ونقل التبعيات من androidTestImplementation إلى testImplementation. النماذج الوهمية (MockK, Mockito) تعمل مع Robolectric دون تغيير — فهي مستقلة عن المنصة.

قيود الانتقال

لا يدعم Robolectric: اختبار الكاميرا (CameraX) و NFC و Bluetooth والقياسات الحيوية والعمل مع الملفات الحقيقية والمكتبات الأصلية. هذه السيناريوهات تتطلب اختبارات أدوات على المحاكي. كما لا يعيد Robolectric إنتاج العرض الحقيقي — فاختبارات التخطيط أفضل عبر Compose Test Rule أو Espresso. ومع ذلك، للتحقق من منطق الأعمال والتنقل وحالات ViewModel، يستبدل Robolectric المحاكي بالكامل مع تسريع 10 أضعاف.

التوافق مع إصدارات Java و Kotlin

يتطلب Robolectric JDK 11 أو أعلى وهو متوافق مع AGP (Android Gradle Plugin) من 7.0 حتى أحدث إصدار مستقر. مدير SDK في Robolectric يقوم تلقائياً بتنزيل إصدارات Android API المطلوبة عند التشغيل الأول — وهي عملية لمرة واحدة. لخوادم CI، يُوصى بتحميل SDK مسبقاً عبر sdkmanager لتجنب التأخير في أول تشغيل للاختبارات. تحديث Robolectric إلى إصدار جديد لا يتطلب عادة تغييرات في كود الاختبارات، فقط تحديث رقم التبعية في build.gradle.

التكامل مع MockK و Mockito

Robolectric متوافق مع أطر المحاكاة الشائعة: MockK لـ Kotlin و Mockito لـ Java. تُستخدم النماذج الوهمية لعزل التبعيات: المستودعات وعملاء API و SharedPreferences. القاعدة الأساسية هي عدم محاكاة فئات Android SDK — لهذا توجد كائنات الظل. قم بمحاكاة طبقات التطبيق فقط: UseCase و Repository و DataSource ومكونات منطق الأعمال الأخرى. هذا المزيج من كائنات الظل والنماذج الوهمية يوفر أقصى مرونة بأقل جهد في كتابة الاختبارات.

الأسئلة الشائعة

ما الفرق بين Robolectric و Espresso؟

Espresso هو إطار عمل أدوات يُشغّل على محاكي أو جهاز. Robolectric هو إطار عمل اختبارات وحدة يعمل على JVM. يختبر Espresso السلوك الحقيقي، بينما يختبر Robolectric المنطق المعزول في بيئة ظل. يكمل كل منهما الآخر.

هل يمكن اختبار Jetpack Compose مع Robolectric؟

نعم، يدعم Robolectric Jetpack Compose بدءاً من الإصدار 4.8. تُنفّذ اختبارات مكونات Compose باستخدام ComposeTestRule، بشكل مشابه للمحاكي. ومع ذلك، لا تتحقق اختبارات Compose على Robolectric من العرض الحقيقي — فقط منطق التركيب.

كيف يعمل Robolectric مع وحدات Gradle؟

يدعم Robolectric المشاريع متعددة الوحدات. تُكوّن كل وحدة بشكل منفصل مع مانيفستها ومواردها الخاصة. للوحدات دون مكونات واجهة مستخدم، يكفي وجود وحدة مكتبة دون إضافة Android. في المشاريع الكبيرة بعشرات الوحدات، تُشغّل اختبارات Robolectric لكل وحدة بالتوازي، مما يعطي مكسباً إضافياً في السرعة مقارنة بالتتابع على المحاكي.

لماذا قد لا يعثر Robolectric على الموارد؟

مشكلة الموارد تحدث إذا لم يكن في build.gradle unitTests.includeAndroidResources = true أو كانت تعليمة @Config مفقودة بالمسار الصحيح للمانيفست. يستخدم Robolectic الموارد المُجمّعة من build/intermediates.

كيفية تصحيح أخطاء اختبارات Robolectric؟

تُصحّح أخطاء اختبارات Robolectric كاختبارات Java/Kotlin عادية في Android Studio. نقاط التوقف والتصحيح خطوة بخطوة وتفحص كائنات الظل وحالتها متاحة. يتم تفعيل التسجيل عبر -Drobolectric.logging=debug في خيارات VM.

الخلاصة

  • Robolectric — إطار عمل لاختبارات الوحدة السريعة لأندرويد على JVM دون محاكي
  • كائنات الظل تستبدل أكثر من 200 فئة من Android SDK، محاكية سلوكها
  • دورة حياة Activity و Fragment تُدار عبر ActivityController مع التحقق من الحالات
  • اختبار النوايا عبر ShadowActivity يتيح التحقق من التنقل ونقل البيانات
  • التكامل مع JUnit و Gradle لا يتطلب مشغّلات أدوات إضافية
  • تعليمة @Config تحدد إصدار API واللغة وتكوين الشاشة والموارد
  • Robolectric و Espresso يكملان بعضهما: اختبارات وحدة سريعة مقابل اختبارات أدوات

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا