Robolectric هو إطار عمل لاختبارات الوحدة لتطبيقات أندرويد يتيح تشغيل الاختبارات مباشرة على JVM دون محاكي أو جهاز فعلي. يعترض استدعاءات Android SDK ويوفر كائنات ظل (shadow-objects) تحاكي سلوك المكونات الحقيقية. وفقاً لـ Robolectric Documentation, 2025، تستبدل كائنات الظل حوالي 15 ألف فئة من Android API، مما يضمن عزل الاختبارات عن المنصة.
الرئيسي
Robolectric هو إطار عمل مفتوح المصدر أُنشئ في 2010 لتسريع اختبار تطبيقات أندرويد. بدلاً من التشغيل على محاكي أو جهاز، يوفر Robolectric تطبيقات ظل لفئات Android SDK تعمل مباشرة على الآلة الافتراضية لجافا (JVM). هذا يسمح بتنفيذ آلاف الاختبارات في ثوانٍ.
يتطلب اختبار أندرويد التقليدي تشغيل التطبيق على محاكي، مما يستغرق 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 في مشروع Gradle إضافة التبعية testImplementation "org.robolectric:robolectric:4.x". من الضروري أيضاً تحديد إعداد androidsdk في ملف build.gradle وإضافة إذن android:testInstrumentationRunner. لا حاجة لإضافة إضافة اختبارات Android للعمل مع Robolectric.
بعد إضافة التبعية، يجب تكوين الدليل الخاص بالمانيفست والموارد والأصول. يجد Robolectric تلقائياً AndroidManifest.xml، ولكن قد تحتاج إلى تحديد المسار يدوياً عبر تعليمة @Config أو خصائص النظام. للمشاريع متعددة الوحدات، يُحدد الإعداد بشكل منفصل لكل وحدة.
// 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 بتجاوز معلمات الاختبار: sdk (إصدار API)، manifest (المسار إلى المانيفست)، qualifiers (تكوين الشاشة، اللغة). هذا مفيد لاختبار سلوك التطبيق على إصدارات مختلفة من أندرويد واتجاهات الشاشة والإعدادات المحلية.
تُكتب اختبارات Robolectric كاختبارات وحدة عادية باستخدام @RunWith(RobolectricTestRunner.class) لـ JUnit 4 أو عبر RobolectricExtension لـ JUnit 5. ActivityController يدير دورة حياة Activity: create() و start() و resume() و pause() و stop() و destroy(). هذا يسمح باختبار كل انتقال حالة بالتفصيل.
لاختبار Activity يُستخدم ActivityController الذي يمر بالتسلسل عبر مراحل دورة الحياة. الوصول إلى Activity يتم عبر controller.get(). جميع مكونات العرض متاحة عبر findViewById كما في التطبيق الحقيقي. تسمح كائنات الظل بالتحقق من النصوص والرؤية والألوان وخصائص العرض الأخرى.
@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 صحيحة.
@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 مثالي لـ اختبارات الوحدة السريعة والتحقق من منطق واجهة المستخدم ومكونات الأعمال والمستودعات. المحاكي ضروري لاختبارات الأدوات والتحقق من التكامل مع API واختبار الكاميرا وأجهزة الاستشعار والأداء.
| الخاصية | Robolectric | المحاكي |
|---|---|---|
| السرعة | ~5 ثوانٍ لكل 100 اختبار | ~5 دقائق لكل 100 اختبار |
| التشغيل | بدون بناء APK | يتطلب بناء APK |
| API حقيقي | محاكاة ظل | Android SDK أصلي |
| جاهز للاستخدام | JUnit فقط | أي أطر عمل |
Robolectric مناسب تماماً لاختبار ViewModel و Repository و UseCase — المكونات التي تستخدم Android SDK ولكنها لا تتطلب واجهة مستخدم حقيقية. ViewModel يُختبر عبر اختبار JUnit عادي مع RobolectricExtension، بينما تعمل مكونات دورة الحياة (LiveData, StateFlow) في بيئة الظل دون نماذج وهمية (mocks).
يدعم Robolectric LiveData بشكل مباشر: يمكنك الاشتراك في LiveData في الاختبار، وتغيير الحالة عبر ViewModel والتحقق من القيمة المُرسلة. للعمليات غير المتزامنة يُستخدم InstantTaskExecutorRule أو runBlocking للكوروتينات. هذا يلغي الحاجة إلى محاكاة المكونات المعمارية.
@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]).
يدعم Robolectric اختبار ContentProvider عبر Robolectric.buildContentProvider(). يمكنك التحقق من عمليات CRUD والاستعلامات بمطابقة URI ومعالجة أذونات الوصول. الموارد (النصوص والألوان والأبعاد) متاحة أيضاً عبر RuntimeEnvironment.application.resources، مما يسمح باختبار الكود الذي يعتمد على الموارد.
يتطلب الانتقال من اختبارات الأدوات إلى 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 أضعاف.
يتطلب Robolectric JDK 11 أو أعلى وهو متوافق مع AGP (Android Gradle Plugin) من 7.0 حتى أحدث إصدار مستقر. مدير SDK في Robolectric يقوم تلقائياً بتنزيل إصدارات Android API المطلوبة عند التشغيل الأول — وهي عملية لمرة واحدة. لخوادم CI، يُوصى بتحميل SDK مسبقاً عبر sdkmanager لتجنب التأخير في أول تشغيل للاختبارات. تحديث Robolectric إلى إصدار جديد لا يتطلب عادة تغييرات في كود الاختبارات، فقط تحديث رقم التبعية في build.gradle.
Robolectric متوافق مع أطر المحاكاة الشائعة: MockK لـ Kotlin و Mockito لـ Java. تُستخدم النماذج الوهمية لعزل التبعيات: المستودعات وعملاء API و SharedPreferences. القاعدة الأساسية هي عدم محاكاة فئات Android SDK — لهذا توجد كائنات الظل. قم بمحاكاة طبقات التطبيق فقط: UseCase و Repository و DataSource ومكونات منطق الأعمال الأخرى. هذا المزيج من كائنات الظل والنماذج الوهمية يوفر أقصى مرونة بأقل جهد في كتابة الاختبارات.
الأسئلة الشائعة
Espresso هو إطار عمل أدوات يُشغّل على محاكي أو جهاز. Robolectric هو إطار عمل اختبارات وحدة يعمل على JVM. يختبر Espresso السلوك الحقيقي، بينما يختبر Robolectric المنطق المعزول في بيئة ظل. يكمل كل منهما الآخر.
نعم، يدعم Robolectric Jetpack Compose بدءاً من الإصدار 4.8. تُنفّذ اختبارات مكونات Compose باستخدام ComposeTestRule، بشكل مشابه للمحاكي. ومع ذلك، لا تتحقق اختبارات Compose على Robolectric من العرض الحقيقي — فقط منطق التركيب.
يدعم Robolectric المشاريع متعددة الوحدات. تُكوّن كل وحدة بشكل منفصل مع مانيفستها ومواردها الخاصة. للوحدات دون مكونات واجهة مستخدم، يكفي وجود وحدة مكتبة دون إضافة Android. في المشاريع الكبيرة بعشرات الوحدات، تُشغّل اختبارات Robolectric لكل وحدة بالتوازي، مما يعطي مكسباً إضافياً في السرعة مقارنة بالتتابع على المحاكي.
مشكلة الموارد تحدث إذا لم يكن في build.gradle unitTests.includeAndroidResources = true أو كانت تعليمة @Config مفقودة بالمسار الصحيح للمانيفست. يستخدم Robolectic الموارد المُجمّعة من build/intermediates.
تُصحّح أخطاء اختبارات Robolectric كاختبارات Java/Kotlin عادية في Android Studio. نقاط التوقف والتصحيح خطوة بخطوة وتفحص كائنات الظل وحالتها متاحة. يتم تفعيل التسجيل عبر -Drobolectric.logging=debug في خيارات VM.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا