يمكنك اختبار تطبيق 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.DarkMode(): يتجاهل إعدادات النظام ويستخدم المظهر الداكن أو المظهر الفاتح.DeviceConfigurationOverride.FontScale(): تلغي مقياس خط النظام.DeviceConfigurationOverride.FontWeightAdjustment(): تلغي هذه السمة تعديل سُمك الخط في النظام.-
DeviceConfigurationOverride.ForcedSize(): تفرض هذه السمة مقدارًا معيّنًا من المساحة بغض النظر عن حجم الجهاز. -
DeviceConfigurationOverride.LayoutDirection(): تلغي اتجاه التصميم (من اليمين إلى اليسار أو من اليسار إلى اليمين). -
DeviceConfigurationOverride.Locales(): تلغي اللغة. DeviceConfigurationOverride.RoundScreen(): يتم تجاهل هذه السمة إذا كانت الشاشة دائرية.
لتطبيق عملية تجاوز محدّدة، عليك تضمين المحتوى الذي يتم اختباره في استدعاء الدالة 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") } }
التعامل المخصّص مع حالات الأعطال في الاختبارات
عند تعذُّر تأكيد صحة البيانات، غالبًا ما يتطلّب تصحيح أخطاء اختبارات واجهة المستخدم فحص حالة الشاشة والتسلسل الهرمي للتركيب.
توفّر Compose مسارًا أصليًا لمعالجة الأعطال من أجل تبسيط عمليات التشخيص. يمكنك التقاط لقطات شاشة وتسلسل هرمي لواجهة المستخدم تلقائيًا عند حدوث خطأ، أو تسجيل معالِجات مخصّصة لإعادة توجيه بيانات القياس عن أعطال التطبيق إلى أدوات خارجية.
ضبط معالجة الأخطاء
لضبط معالجة الأخطاء، مرِّر عنصر TestFailurePolicy إلى ComposeUiTestConfig.
تسجيل بيانات الأعطال المضمّنة
لالتقاط لقطات شاشة وتسلسل هرمي لواجهة المستخدم عند تعذُّر الاختبار، اضبط السمتَين screenshotCaptureMode وuiHierarchyCaptureMode في TestFailurePolicy.
class MyComposeTest { private val customConfig = ComposeUiTestConfig( failurePolicy = TestFailurePolicy( screenshotCaptureMode = TestFailurePolicy.CaptureMode.Enabled, uiHierarchyCaptureMode = TestFailurePolicy.CaptureMode.Enabled ) ) @Test fun myFirstTest() = runComposeUiTest(config = customConfig) { // ... } }
استخدام معالج أخطاء مخصّص
لتحديد سلوك مخصّص لحالات تعذُّر الاختبار، أضِف
TestFailureHandler إلى قائمة failureHandlers. يتلقّى كل معالج كائن FailureContext يحتوي على الخطأ الأصلي وقائمة بالعناصر التي تم إنشاؤها بواسطة معالجات خط الأنابيب السابقة.
class MyComposeTestWithHandler { private val customConfig = ComposeUiTestConfig( failurePolicy = TestFailurePolicy( screenshotCaptureMode = TestFailurePolicy.CaptureMode.Enabled, failureHandlers = listOf( TestFailureHandler { context -> val screenshot = context.artifacts.firstOrNull { it.type == FailureArtifact.Type.Screenshot } // ... } ) ) ) @get:Rule val rule = createComposeRule(config = customConfig) // ... }
ضبط عمليات الالتقاط لحزمة اختبار كاملة
يمكنك تفعيل عمليات التقاط بيانات الأخطاء لمجموعة اختبارات كاملة من خلال تمرير وسيطات مشغّل قياس حالة التطبيق في ملف build.gradle الخاص بالوحدة. يُغنيك ذلك عن تعديل ملفات الاختبار الفردية.
// build.gradle.kts
android {
defaultConfig {
// ...
testInstrumentationRunnerArguments["androidx.compose.ui.test.failure.isUiHierarchyCaptureEnabled"] = "true"
testInstrumentationRunnerArguments["androidx.compose.ui.test.failure.isScreenshotCaptureEnabled"] = "true"
}
}
أولوية الإعدادات
يقيّم إطار العمل كلاً من وسيطات TestFailurePolicy المحلية ووسيطات برنامج التشغيل على مستوى المجموعة:
- إذا ضبطت الوضع على
CaptureMode.Enabled/Disabledبشكل صريح فيfailurePolicyالاختبار، سيتم تجاهل وسيطة المشغّل. - إذا ضبطت الوضع على
CaptureMode.Unspecified(أو تركتfailurePolicyعلىnull)، سيعود إطار العمل إلى وسيطة المشغّل.
موارد إضافية
- اختبار التطبيقات على Android: تقدّم الصفحة المقصودة الرئيسية لاختبار Android نظرة عامة أوسع على أساسيات الاختبار وأساليبه.
- أساسيات الاختبار: مزيد من المعلومات عن المفاهيم الأساسية لاختبار تطبيق Android
- الاختبارات المحلية: يمكنك إجراء بعض الاختبارات محليًا على محطة العمل الخاصة بك.
- اختبارات لقياس حالة التطبيق: من الممارسات الجيدة أيضًا إجراء اختبارات لقياس حالة التطبيق. أي الاختبارات التي يتم إجراؤها مباشرةً على الجهاز.
- التكامل المستمر: يتيح لك التكامل المستمر دمج اختباراتك في مسار النشر.
- اختبار أحجام الشاشات المختلفة: بما أنّ المستخدمين يتوفّر لديهم العديد من الأجهزة، عليك اختبار أحجام الشاشات المختلفة.
- Espresso: على الرغم من أنّ Espresso مُصمَّمة لواجهات المستخدم المستندة إلى العرض، إلا أنّ معرفة أدوات Espresso يمكن أن تكون مفيدة في بعض جوانب اختبار Compose.