اختبار الأجزاء غير النشطة

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

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

  • ويجب ألا يكون الجزء معتمدًا على نشاط أو جزء رئيسي محدد.
  • ويجب عدم إنشاء عرض هرمي للجزء ما لم يكن الجزء مرئيًا للمستخدم.

للمساعدة في إعداد شروط إجراء هذه الاختبارات، توفّر مكتبة AndroidX fragment-testing الفئة FragmentScenario لإنشاء الأجزاء وتغيير Lifecycle.State الخاصة بها.

إعلان التبعيات

لاستخدام FragmentScenario، يجب تحديد عنصر fragment-testing-manifest في ملف build.gradle لتطبيقك باستخدام debugImplementation، والعنصر fragment-testing باستخدام androidTestImplementation كما هو موضّح في المثال التالي:

رائع

dependencies {
    def fragment_version = "1.8.1"

    debugImplementation "androidx.fragment:fragment-testing-manifest:$fragment_version"

    androidTestImplementation "androidx.fragment:fragment-testing:$fragment_version"
}

Kotlin

dependencies {
    val fragment_version = "1.8.1"

    debugImplementation("androidx.fragment:fragment-testing-manifest:$fragment_version")

    androidTestImplementation("androidx.fragment:fragment-testing:$fragment_version")
}

تستخدِم أمثلة الاختبار على هذه الصفحة تأكيدات من مكتبتَي Espresso وTruth. للحصول على معلومات عن مكتبات الاختبار والتأكيد الأخرى المتاحة، يُرجى الاطّلاع على إعداد المشروع لاختبار AndroidX.

إنشاء جزء

تشمل FragmentScenario الطرق التالية لإطلاق الأجزاء في الاختبارات:

  • launchInContainer()، لاختبار واجهة المستخدم للجزء ويرفق FragmentScenario الجزء بوحدة التحكم في العرض الجذري للنشاط. هذا النشاط الذي يحتوي على فارغ فارغ.
  • launch()، للاختبار بدون واجهة المستخدم للجزء. FragmentScenario يتم إرفاق هذا النوع من الأجزاء بنشاط فارغ، أي نشاط لا يتضمن طريقة عرض جذر.

بعد تشغيل أحد أنواع الأجزاء هذه، تعمل السمة FragmentScenario على نقل الجزء قيد الاختبار إلى حالة محدّدة. هذه الحالة هي RESUMED تلقائيًا، ولكن يمكنك إلغاء ذلك باستخدام الوسيطة initialState. وتشير حالة RESUMED إلى أن الجزء قيد التشغيل ومرئي للمستخدم. يمكنك تقييم معلومات حول عناصر واجهة المستخدم باستخدام اختبارات واجهة مستخدم Espresso.

توضح أمثلة التعليمات البرمجية التالية كيفية تشغيل الجزء باستخدام كل طريقة:

مثال على launchInContainer()

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEventFragment() {
        // The "fragmentArgs" argument is optional.
        val fragmentArgs = bundleOf(“selectedListItem” to 0)
        val scenario = launchFragmentInContainer<EventFragment>(fragmentArgs)
        ...
    }
}

مثال على()launch

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEventFragment() {
        // The "fragmentArgs" arguments are optional.
        val fragmentArgs = bundleOf("numElements" to 0)
        val scenario = launchFragment<EventFragment>(fragmentArgs)
        ...
    }
}

تقديم التبعيات

إذا كانت أجزائك تابعة، يمكنك تقديم إصدارات اختبارية منها من خلال توفير FragmentFactory مخصّصة للسمة launchInContainer() أو launch().

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEventFragment() {
        val someDependency = TestDependency()
        launchFragmentInContainer {
            EventFragment(someDependency)
        }
        ...
    }
}

لمزيد من المعلومات حول استخدام FragmentFactory لتوفير العناصر التابعة للأجزاء، يُرجى الاطّلاع على مدير التجزئة.

نقل الجزء إلى حالة جديدة

في اختبارات واجهة المستخدم في تطبيقك، يكفي عادةً بدء الجزء قيد الاختبار وبدء اختباره من حالة RESUMED. ومع ذلك، يمكنك في اختبارات الوحدة الأكثر دقة تقييم سلوك الجزء أثناء انتقاله من حالة دورة حياة إلى أخرى. يمكنك تحديد الحالة الأولية من خلال تمرير الوسيطة initialState إلى أي من دوال launchFragment*().

لنقل الجزء إلى مراحل نشاط مختلفة، يمكنك استدعاء السمة moveToState(). تتيح هذه الطريقة استخدام الحالات التالية كوسيطات: CREATED وSTARTED وRESUMED وDESTROYED. تحاكي هذه الطريقة موقفًا يغير فيه الجزء أو النشاط الذي يحتوي على الجزء حالته لأي سبب من الأسباب.

يفتح المثال التالي جزءًا اختباريًا في حالة INITIALIZED ثم ينقله إلى الحالة RESUMED:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEventFragment() {
        val scenario = launchFragmentInContainer<EventFragment>(
            initialState = Lifecycle.State.INITIALIZED
        )
        // EventFragment has gone through onAttach(), but not onCreate().
        // Verify the initial state.
        scenario.moveToState(Lifecycle.State.RESUMED)
        // EventFragment moves to CREATED -> STARTED -> RESUMED.
        ...
    }
}

إعادة إنشاء الجزء

إذا كان تطبيقك يعمل على جهاز منخفضة الموارد، قد يتلف النظام النشاط الذي يحتوي على الجزء. ويتطلب هذا الموقف من تطبيقك إعادة إنشاء الجزء عندما يعود المستخدم إليه. لمحاكاة هذا الموقف، عليك الاتصال بالرقم recreate():

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEventFragment() {
        val scenario = launchFragmentInContainer<EventFragment>()
        scenario.recreate()
        ...
    }
}

يؤدي FragmentScenario.recreate() إلى إتلاف الجزء ومضيفه، ثم إعادة إنشاؤه. عندما تُعيد الفئة FragmentScenario إنشاء الجزء قيد الاختبار، يعود الجزء إلى حالة دورة الحياة التي كان عليها قبل إتلافه.

التفاعل مع أجزاء واجهة المستخدم

لتشغيل إجراءات واجهة المستخدم في الجزء قيد الاختبار، يمكنك استخدام مُطابقات عرض Espresso للتفاعل مع العناصر في العرض:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEventFragment() {
        val scenario = launchFragmentInContainer<EventFragment>()
        onView(withId(R.id.refresh)).perform(click())
        // Assert some expected behavior
        ...
    }
}

إذا كنت بحاجة إلى استدعاء طريقة على الجزء نفسه، مثل الاستجابة لتحديد في قائمة الخيارات، يمكنك إجراء ذلك بأمان من خلال الحصول على مرجع إلى الجزء باستخدام FragmentScenario.onFragment() وتمرير FragmentAction:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEventFragment() {
        val scenario = launchFragmentInContainer<EventFragment>()
        scenario.onFragment { fragment ->
            fragment.myInstanceMethod()
        }
    }
}

اختبار إجراءات مربّعات الحوار

وتتيح FragmentScenario أيضًا اختبار أجزاء مربّع الحوار. على الرغم من أن أجزاء مربعات الحوار تحتوي على عناصر واجهة المستخدم، يتم ملء تنسيقها في نافذة منفصلة، وليس في النشاط نفسه. لهذا السبب، استخدِم FragmentScenario.launch() لاختبار أجزاء مربّعات الحوار.

يختبر المثال التالي عملية إغلاق مربّع الحوار:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testDismissDialogFragment() {
        // Assumes that "MyDialogFragment" extends the DialogFragment class.
        with(launchFragment<MyDialogFragment>()) {
            onFragment { fragment ->
                assertThat(fragment.dialog).isNotNull()
                assertThat(fragment.requireDialog().isShowing).isTrue()
                fragment.dismiss()
                fragment.parentFragmentManager.executePendingTransactions()
                assertThat(fragment.dialog).isNull()
            }
        }

        // Assumes that the dialog had a button
        // containing the text "Cancel".
        onView(withText("Cancel")).check(doesNotExist())
    }
}