تعمل الأنشطة كحاويات لكل تفاعل من جانب المستخدم داخل تطبيقك، لذا من المهم اختبار سلوك أنشطة تطبيقك أثناء الأحداث على مستوى الجهاز، مثل ما يلي:
- يقاطع تطبيق آخر، مثل تطبيق الهاتف على الجهاز، نشاط تطبيقك.
- يدمّر النظام نشاطك ويعيد إنشائه.
- يضع المستخدم نشاطك في بيئة جديدة لعرض النوافذ، مثل وضع صورة داخل صورة أو وضع النوافذ المتعددة.
على وجه الخصوص، من المهم التأكّد من أنّ نشاطك يتصرف بشكلٍ صحيح استجابةً للأحداث الموضّحة في مراحل النشاط.
يصف هذا الدليل كيفية تقييم قدرة تطبيقك على الحفاظ على سلامة البيانات وتوفير تجربة مستخدم جيدة أثناء انتقال أنشطة تطبيقك خلال حالات مختلفة في دورات حياتها.
اختبار الأنشطة في Compose
عند اختبار تطبيق تم إنشاؤه باستخدام Jetpack Compose، يمكنك عادةً استخدام
createAndroidComposeRule لتشغيل نشاطك والتفاعل مع مكوّنات واجهة المستخدم.
ومع ذلك، يتطلب اختبار الأحداث على مستوى الجهاز، مثل تغييرات الإعدادات أو وضع النشاط في الخلفية أو تدميره من قِبل النظام، التلاعب بدورة حياة النشاط مباشرةً. لإجراء ذلك، يمكنك استخدام الـ
أساسي ActivityScenario إطار عمل.
تتولّى قاعدة اختبار Compose تلقائيًا عملية تضمين هذا السيناريو وإدارته نيابةً عنك. خلال هذا الدليل، ستظهر لك النمط التالي المستخدَم لسدّ الفجوة بين اختبار واجهة المستخدم الحديث وإدارة دورة الحياة العادية:
@get:Rule
val composeTestRule = createAndroidComposeRule<MyActivity>()
@Test fun testEvent() {
val scenario = composeTestRule.activityRule.scenario
// ...
}
توجيه حالة النشاط
يتضمّن أحد الجوانب الرئيسية لاختبار أنشطة تطبيقك وضع أنشطة تطبيقك في حالات معيّنة. لتحديد هذا الجزء "المعطى" من اختباراتك، استخدِم
مثيلات ActivityScenario، وهو جزء من مكتبة
AndroidX Test. باستخدام هذه الفئة، يمكنك وضع نشاطك في حالات تحاكي الأحداث على مستوى الجهاز.
ActivityScenario هي واجهة برمجة تطبيقات من عدّة منصات يمكنك استخدامها في اختبارات الوحدات المحلية واختبارات التكامل على الجهاز فقط على حد سواء. على جهاز حقيقي أو افتراضي، توفّر ActivityScenario أمانًا على مستوى سلسلة التعليمات، ما يؤدي إلى مزامنة الأحداث بين سلسلة تعليمات قياس حالة التطبيق للاختبار وسلسلة التعليمات التي تشغّل نشاطك قيد الاختبار.
تتلاءم واجهة برمجة التطبيقات بشكلٍ خاص مع تقييم سلوك النشاط قيد الاختبار عند تدميره أو إنشائه. يعرض هذا القسم حالات الاستخدام الأكثر شيوعًا المرتبطة بواجهة برمجة التطبيقات هذه.
إنشاء نشاط
لإنشاء النشاط قيد الاختبار، أضِف الرمز البرمجي الموضّح في المقتطف التالي:
@RunWith(AndroidJUnit4::class)
class MyTestSuite {
@Test fun testEvent() {
launchActivity<MyActivity>().use {
}
}
}
بعد إنشاء النشاط، تنقل ActivityScenario النشاط إلى الحالة RESUMED. تشير هذه الحالة إلى أنّ نشاطك قيد التشغيل ومرئي للمستخدمين. في هذه الحالة، يمكنك التفاعل مع الدوال المركّبة لنشاطك
باستخدام واجهات برمجة تطبيقات اختبار Compose.
تنصح Google باستدعاء close على النشاط عند اكتمال الاختبار.
يؤدي ذلك إلى تنظيف الموارد المرتبطة وتحسين ثبات اختباراتك. تنفّذ ActivityScenario واجهة Closeable، لذا يمكنك تطبيق الإضافة use لإغلاق النشاط تلقائيًا.
بدلاً من ذلك، يمكنك استخدام createAndroidComposeRule لتشغيل النشاط تلقائيًا
قبل كل اختبار، والتعامل مع عملية الإيقاف، ومنحك إمكانية الوصول إلى
كلٍّ من طرق اختبار واجهة مستخدم Compose وActivityScenario الأساسي. يوضّح المثال التالي كيفية تحديد قاعدة والحصول على مثال لسيناريو منها:
@RunWith(AndroidJUnit4::class)
class MyTestSuite {
@get:Rule
val composeTestRule = createAndroidComposeRule<MyActivity>()
@Test fun testEvent() {
val scenario = composeTestRule.activityRule.scenario
}
}
نقل النشاط إلى حالة جديدة
لنقل النشاط إلى حالة مختلفة، مثل CREATED أو STARTED، استدعِ moveToState. يحاكي هذا الإجراء حالة يتم فيها إيقاف نشاطك أو إيقافه مؤقتًا، على التوالي، بسبب مقاطعته من قِبل تطبيق آخر أو إجراء نظام.
يظهر مثال على استخدام moveToState في مقتطف الرمز البرمجي التالي:
@RunWith(AndroidJUnit4::class)
class MyTestSuite {
@Test fun testEvent() {
launchActivity<MyActivity>().use { scenario ->
scenario.moveToState(State.CREATED)
}
}
}
تحديد حالة النشاط الحالية
لتحديد الحالة الحالية للنشاط قيد الاختبار، احصل على قيمة الحقل state ضِمن عنصر ActivityScenario. من المفيد بشكلٍ خاص التحقّق من حالة النشاط قيد الاختبار إذا كان النشاط يعيد التوجيه إلى نشاط آخر أو ينهي نفسه، كما هو موضّح في مقتطف الرمز البرمجي التالي:
@RunWith(AndroidJUnit4::class)
class MyTestSuite {
@Test fun testEvent() {
launchActivity<MyActivity>().use { scenario ->
scenario.onActivity { activity ->
startActivity(Intent(activity, MyOtherActivity::class.java))
}
val originalActivityState = scenario.state
}
}
}
إعادة إنشاء النشاط
عندما يكون الجهاز منخفض الموارد، قد يدمّر النظام نشاطًا، ما يتطلب من تطبيقك إعادة إنشاء هذا النشاط عندما يعود المستخدم إلى تطبيقك. لمحاكاة هذه الظروف، استدعِ recreate:
@RunWith(AndroidJUnit4::class)
class MyTestSuite {
@Test fun testEvent() {
launchActivity<MyActivity>().use { scenario ->
scenario.recreate()
}
}
}
تحتفظ فئة ActivityScenario بحالة مثيل النشاط المحفوظة وأي كائنات تم وضع علامة عليها باستخدام @NonConfigurationInstance. يتم تحميل هذه الكائنات في المثيل الجديد لنشاطك قيد الاختبار.
استرداد نتائج النشاط
للحصول على رمز النتيجة أو البيانات المرتبطة بنشاط مكتمل، احصل على قيمة الحقل result ضِمن عنصر ActivityScenario. باستخدام createAndroidComposeRule، يمكنك بسهولة تشغيل إجراء واجهة المستخدم الذي ينهي النشاط، كما هو موضّح في مقتطف الرمز البرمجي التالي:
@RunWith(AndroidJUnit4::class)
class MyTestSuite {
@get:Rule
val composeTestRule = createAndroidComposeRule<MyActivity>()
@Test fun testResult() {
composeTestRule.onNodeWithTag("finish_button").performClick()
val scenario = composeTestRule.activityRule.scenario
val resultCode = scenario.result.resultCode
val resultData = scenario.result.resultData
}
}
تشغيل الإجراءات في النشاط
جميع الطرق ضِمن ActivityScenario هي عمليات حظر، لذا تتطلب منك واجهة برمجة التطبيقات تشغيلها في سلسلة محادثات أدوات الاختبار.
لتشغيل الإجراءات في نشاطك قيد الاختبار، استخدِم واجهات برمجة تطبيقات اختبار Compose للتفاعل مع الدوال المركّبة:
@RunWith(AndroidJUnit4::class)
class MyTestSuite {
@get:Rule
val composeTestRule = createAndroidComposeRule<MyActivity>()
@Test fun testEvent() {
composeTestRule.onNodeWithText("Refresh").performClick()
}
}
إذا كنت بحاجة إلى استدعاء طريقة في النشاط نفسه، يمكنك إجراء ذلك بأمان باستخدام onActivity:
@RunWith(AndroidJUnit4::class)
class MyTestSuite {
@Test fun testEvent() {
launchActivity<MyActivity>().use { scenario ->
scenario.onActivity { activity ->
activity.handleSwipeToRefresh()
}
}
}
}
مراجع إضافية
لمزيد من المعلومات عن الاختبار، اطّلِع على المراجع الإضافية التالية: