Menguji fragmen Anda

Topik ini menjelaskan cara menyertakan API yang disediakan framework dalam pengujian yang mengevaluasi perilaku setiap fragmen.

Fragmen berfungsi sebagai penampung yang dapat digunakan kembali dalam aplikasi Anda, sehingga Anda dapat menyajikan tata letak antarmuka pengguna yang sama di berbagai aktivitas dan konfigurasi tata letak. Dengan keserbagunaannya, sangatlah penting untuk memvalidasi bahwa fragmen memberikan pengalaman yang konsisten dan efisien akan resource. Perhatikan hal berikut:

  • Fragmen Anda tidak boleh bergantung pada induk aktivitas atau fragmen tertentu.
  • Anda tidak boleh membuat hierarki tampilan fragmen kecuali jika fragmen tersebut terlihat oleh pengguna.

Untuk membantu menyiapkan kondisi dalam menjalankan pengujian, library fragment-testing AndroidX menyediakan class FragmentScenario untuk membuat fragmen dan mengubah Lifecycle.State.

Mendeklarasikan dependensi

Untuk menggunakan FragmentScenario, tentukan artefak fragment-testing-manifest di file build.gradle aplikasi menggunakan debugImplementation, dan artefak fragment-testing menggunakan androidTestImplementation seperti yang ditampilkan dalam contoh berikut:

Groovy

dependencies {
    def fragment_version = "1.8.5"

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

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

Kotlin

dependencies {
    val fragment_version = "1.8.5"

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

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

Contoh pengujian di halaman ini menggunakan pernyataan dari library Espresso dan Truth. Untuk informasi tentang library pengujian dan pernyataan tersedia lainnya, lihat Menyiapkan project untuk Pengujian AndroidX.

Membuat fragmen

FragmentScenario menyertakan metode berikut untuk meluncurkan fragmen dalam pengujian:

  • launchInContainer(), untuk menguji antarmuka pengguna fragmen. FragmentScenario akan melampirkan fragmen ke pengontrol tampilan root aktivitas. Aktivitas penampung ini bernilai kosong.
  • launch(), untuk menguji tanpa antarmuka pengguna fragmen. FragmentScenario menyertakan jenis fragmen ini ke aktivitas yang kosong dan tidak memiliki tampilan root.

Setelah meluncurkan salah satu jenis fragmen ini, FragmentScenario akan mengalihkan status fragmen yang sedang diuji. Secara default, status ini adalah RESUMED, tetapi Anda dapat menggantinya dengan argumen initialState. Status RESUMED menunjukkan bahwa fragmen sedang berjalan dan terlihat oleh pengguna. Anda dapat mengevaluasi informasi tentang elemen UI-nya menggunakan pengujian UI Espresso.

Contoh kode berikut menunjukkan cara meluncurkan fragmen menggunakan masing-masing metode:

Contoh 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)
        ...
    }
}

Contoh 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)
        ...
    }
}

Menyediakan dependensi

Jika fragmen memiliki dependensi, Anda dapat menyediakan versi uji dependensi tersebut dengan memberikan FragmentFactory kustom ke metode launchInContainer() atau launch().

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

Untuk informasi selengkapnya tentang penggunaan FragmentFactory dalam memberikan dependensi ke fragmen, lihat Pengelola fragmen.

Mengalihkan fragmen ke status baru

Dalam pengujian UI aplikasi, biasanya Anda cukup meluncurkan fragmen yang sedang diuji lalu mulai mengujinya dari status RESUMED. Namun, dalam pengujian unit yang lebih terperinci, Anda mungkin juga perlu mengevaluasi perilaku fragmen saat bertransisi dari satu status siklus proses ke status siklus proses lainnya. Anda dapat menentukan status awal dengan meneruskan argumen initialState ke fungsi launchFragment*() mana pun.

Untuk mengalihkan fragmen ke status siklus proses yang berbeda, panggil moveToState(). Metode ini mendukung status berikut sebagai argumen: CREATED, STARTED, RESUMED, dan DESTROYED. Metode ini menyimulasikan situasi ketika fragmen atau aktivitas yang berisi fragmen Anda mengubah statusnya karena alasan apa pun.

Contoh berikut meluncurkan fragmen pengujian dalam status INITIALIZED, lalu memindahkannya ke status 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.
        ...
    }
}

Membuat ulang fragmen

Jika aplikasi Anda berjalan di perangkat yang kekurangan resource, sistem mungkin akan menghapus aktivitas yang berisi fragmen Anda. Situasi ini mengharuskan aplikasi untuk membuat ulang fragmen saat pengguna kembali ke aplikasi Anda. Untuk menyimulasikan situasi ini, panggil recreate():

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

FragmentScenario.recreate() menghapus fragmen dan host-nya, lalu membuatnya kembali. Jika class FragmentScenario membuat ulang fragmen yang sedang diuji, fragmen tersebut akan kembali ke status siklus proses yang telah ada sebelum dihapus.

Berinteraksi dengan fragmen UI

Untuk memicu tindakan UI dalam fragmen yang sedang diuji, gunakan matcher tampilan Espresso untuk berinteraksi dengan elemen dalam tampilan Anda:

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

Jika Anda perlu memanggil metode pada fragmen itu sendiri, seperti merespons pilihan di menu opsi, Anda dapat aman melakukannya dengan mengambil referensi ke fragmen menggunakan FragmentScenario.onFragment() dan diteruskan dalam FragmentAction:

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

Menguji tindakan dialog

FragmentScenario juga mendukung pengujian fragmen dialog. Meskipun fragmen dialog memiliki elemen UI, tata letaknya diisi dalam jendela terpisah, bukan di aktivitas itu sendiri. Karena alasan ini, gunakan FragmentScenario.launch() untuk menguji fragmen dialog.

Contoh berikut akan menguji proses penutupan dialog:

@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())
    }
}