الأنماط الشائعة

يمكنك اختبار تطبيق Compose باستخدام نُهج وأنماط راسخة.

الاختبار بشكل منفصل

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

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

الوصول إلى النشاط والموارد بعد ضبط المحتوى الخاص بك

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

من الأنماط الشائعة لتحقيق ذلك إنشاء AndroidComposeTestRule باستخدام نشاط فارغ، مثل ComponentActivity.

class MyComposeTest {

    @get:Rule
    val composeTestRule = createAndroidComposeRule<ComponentActivity>()

    @Test
    fun myTest() {
        // Start the app
        composeTestRule.setContent {
            MyAppTheme {
                MainScreen(uiState = exampleUiState, /*...*/)
            }
        }
        val continueLabel = composeTestRule.activity.getString(R.string.next)
        composeTestRule.onNodeWithText(continueLabel).performClick()
    }
}

يُرجى العِلم أنّه يجب إضافة ComponentActivity إلى ملف AndroidManifest.xml الخاص بتطبيقك. يمكنك تفعيل ذلك من خلال إضافة هذا التبعية إلى وحدتك:

debugImplementation("androidx.compose.ui:ui-test-manifest:$compose_version")

خصائص الدلالات المخصّصة

يمكنك إنشاء خصائص دلالات مخصّصة لعرض المعلومات للاختبارات. لإجراء ذلك، عليك تحديد SemanticsPropertyKey جديد وإتاحته باستخدام SemanticsPropertyReceiver.

// Creates a semantics property of type Long.
val PickedDateKey = SemanticsPropertyKey<Long>("PickedDate")
var SemanticsPropertyReceiver.pickedDate by PickedDateKey

يمكنك الآن استخدام هذه السمة في المعدِّل semantics:

val datePickerValue by remember { mutableStateOf(0L) }
MyCustomDatePicker(
    modifier = Modifier.semantics { pickedDate = datePickerValue }
)

من الاختبارات، استخدِم SemanticsMatcher.expectValue للتأكّد من قيمة السمة:

composeTestRule
    .onNode(SemanticsMatcher.expectValue(PickedDateKey, 1445378400)) // 2015-10-21
    .assertExists()

التأكّد من استعادة الحالة

تأكَّد من استعادة حالة عناصر Compose بشكلٍ صحيح عند إعادة إنشاء النشاط أو العملية. يمكنك إجراء عمليات التحقّق هذه بدون الاعتماد على إعادة إنشاء النشاط باستخدام الفئة StateRestorationTester.

تتيح لك هذه الفئة محاكاة إعادة إنشاء عنصر قابل للإنشاء. ويفيد ذلك بشكلٍ خاص في التحقّق من تنفيذ rememberSaveable.


class MyStateRestorationTests {

    @get:Rule
    val composeTestRule = createComposeRule()

    @Test
    fun onRecreation_stateIsRestored() {
        val restorationTester = StateRestorationTester(composeTestRule)

        restorationTester.setContent { MainScreen() }

        // TODO: Run actions that modify the state

        // Trigger a recreation
        restorationTester.emulateSavedInstanceStateRestore()

        // TODO: Verify that state has been correctly restored.
    }
}

اختبار إعدادات الأجهزة المختلفة

يجب أن تتكيّف تطبيقات Android مع العديد من الظروف المتغيّرة: أحجام النوافذ واللغات وأحجام الخطوط والمظهرين الداكن والفاتح وغير ذلك. تستند معظم هذه الظروف إلى القيم على مستوى الجهاز التي يتحكّم بها المستخدم ويتم عرضها باستخدام مثيل Configuration الحالي. يصعب اختبار إعدادات مختلفة مباشرةً في الاختبار لأنّ الاختبار يجب أن يضبط الخصائص على مستوى الجهاز.

DeviceConfigurationOverride هي واجهة برمجة تطبيقات مخصّصة للاختبار فقط تتيح لك محاكاة إعدادات الأجهزة المختلفة بطريقة موضعية للمحتوى @Composable قيد الاختبار.

يحتوي العنصر المصاحب لـ DeviceConfigurationOverride على دوال الإضافة التالية التي تلغي خصائص الإعداد على مستوى الجهاز:

لتطبيق عملية إلغاء معيّنة، عليك تضمين المحتوى قيد الاختبار في استدعاء للدالة DeviceConfigurationOverride() ذات المستوى الأعلى، مع تمرير عملية الإلغاء التي تريد تطبيقها كمعلَمة.

على سبيل المثال، يطبّق الرمز التالي عملية الإلغاء DeviceConfigurationOverride.ForcedSize() لتغيير الكثافة محليًا، ما يجبر العنصر القابل للإنشاء MyScreen على العرض في نافذة كبيرة في الوضع الأفقي، حتى إذا كان الجهاز الذي يتم تشغيل الاختبار عليه لا يتيح حجم النافذة هذا مباشرةً:

composeTestRule.setContent {
    DeviceConfigurationOverride(
        DeviceConfigurationOverride.ForcedSize(DpSize(1280.dp, 800.dp))
    ) {
        MyScreen() // Will be rendered in the space for 1280dp by 800dp without clipping.
    }
}

لتطبيق عمليات إلغاء متعدّدة معًا، استخدِم DeviceConfigurationOverride.then():

composeTestRule.setContent {
    DeviceConfigurationOverride(
        DeviceConfigurationOverride.FontScale(1.5f) then
            DeviceConfigurationOverride.FontWeightAdjustment(200)
    ) {
        Text(text = "text with increased scale and weight")
    }
}

مراجع إضافية

  • اختبار التطبيقات على Android: تقدّم الصفحة المقصودة الرئيسية لاختبار Android نظرة أوسع على أساسيات الاختبار وتقنياته.
  • أساسيات الاختبار: مزيد من المعلومات عن المفاهيم الأساسية لاختبار تطبيق Android.
  • الاختبارات المحلية: يمكنك إجراء بعض الاختبارات محليًا على محطة العمل الخاصة بك.
  • اختبارات لقياس حالة التطبيق: من الممارسات الجيدة أيضًا إجراء اختبارات لقياس حالة التطبيق. أي الاختبارات التي يتم إجراؤها مباشرةً على الجهاز.
  • التكامل المستمر: يتيح لك التكامل المستمر دمج اختباراتك في مسار النشر.
  • **اختبار أحجام الشاشات المختلفة**: بما أنّ هناك العديد من الأجهزة المتاحة للمستخدمين، عليك إجراء اختبارات لأحجام الشاشات المختلفة.
  • Espresso: على الرغم من أنّ Espresso مُصمَّمة لواجهات المستخدم المستندة إلى العرض، إلا أنّ معرفة أدوات Espresso يمكن أن تكون مفيدة في بعض جوانب اختبار Compose.