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

يمكنك اختبار تطبيق 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()

التحقّق من استعادة الحالة

تأكَّد من استعادة حالة عناصر الإنشاء بشكل صحيح عند إعادة إنشاء النشاط أو العملية. يمكنك إجراء عمليات التحقّق هذه بدون الاعتماد على إعادة إنشاء النشاط باستخدام فئة 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()override لتغيير الكثافة محليًا، ما يجبر العنصر القابل للتجميع MyScreen على العرض في نافذة DeviceConfigurationOverride.ForcedSize()عمودية كبيرة، حتى إذا كان الجهاز الذي يتم تشغيل الاختبار عليه لا يتيح حجم النافذة هذا مباشرةً:

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 مخصّص لواجهات مستنِدة إلى الاطّلاع، يمكن أن تكون المعرفة به مفيدة لبعض جوانب اختبار ميزة "الإنشاء".