Pola umum

Anda dapat menguji aplikasi Compose dengan pendekatan dan pola yang sudah mapan.

Pengujian secara terpisah

ComposeTestRule memungkinkan Anda memulai aktivitas yang menampilkan composable apa pun: aplikasi lengkap, satu layar, atau elemen kecil. Sebaiknya periksa juga apakah composable Anda dienkapsulasi dengan benar dan berfungsi secara independen, sehingga memungkinkan pengujian UI yang lebih mudah dan lebih fokus.

Ini tidak berarti Anda hanya akan membuat pengujian UI unit. Pengujian UI yang mencakup sebagian besar UI yang ada juga sangat penting.

Mengakses aktivitas dan resource setelah menetapkan konten Anda sendiri

Sering kali Anda perlu menetapkan konten yang sedang diuji menggunakan composeTestRule.setContent dan juga perlu mengakses resource aktivitas, misalnya untuk menyatakan bahwa teks yang ditampilkan cocok dengan resource string. Namun, Anda tidak dapat memanggil setContent pada aturan yang dibuat dengan createAndroidComposeRule() jika aktivitas sudah memanggilnya.

Pola umum untuk melakukannya adalah dengan membuat AndroidComposeTestRule menggunakan aktivitas kosong seperti 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()
    }
}

Perlu diperhatikan bahwa ComponentActivity harus ditambahkan ke file AndroidManifest.xml aplikasi Anda. Aktifkan dengan menambahkan dependensi ini ke modul:

debugImplementation("androidx.compose.ui:ui-test-manifest:$compose_version")

Properti semantik kustom

Anda dapat membuat properti semantik kustom untuk mengekspos informasi ke pengujian. Untuk melakukannya, tentukan SemanticsPropertyKey baru dan sediakan menggunakan SemanticsPropertyReceiver.

// Creates a semantics property of type Long.
val PickedDateKey = SemanticsPropertyKey<Long>("PickedDate")
var SemanticsPropertyReceiver.pickedDate by PickedDateKey

Sekarang, gunakan properti tersebut di pengubah semantics:

val datePickerValue by remember { mutableStateOf(0L) }
MyCustomDatePicker(
    modifier = Modifier.semantics { pickedDate = datePickerValue }
)

Dari pengujian, gunakan SemanticsMatcher.expectValue untuk menyatakan nilai properti:

composeTestRule
    .onNode(SemanticsMatcher.expectValue(PickedDateKey, 1445378400)) // 2015-10-21
    .assertExists()

Memverifikasi pemulihan status

Pastikan status elemen Compose dipulihkan dengan benar saat aktivitas atau proses dibuat ulang. Lakukan pemeriksaan tersebut tanpa mengandalkan pembuatan ulang aktivitas dengan class StateRestorationTester.

Class ini memungkinkan Anda menyimulasikan pembuatan ulang composable. Hal ini sangat berguna untuk memverifikasi penerapan 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.
    }
}

Menguji berbagai konfigurasi perangkat

Aplikasi Android harus beradaptasi dengan banyak kondisi yang berubah: ukuran jendela, lokal, ukuran font, tema gelap dan terang, dan lainnya. Sebagian besar kondisi ini berasal dari nilai tingkat perangkat yang dikontrol oleh pengguna dan diekspos dengan instance Configuration saat ini. Menguji berbagai konfigurasi secara langsung dalam pengujian sulit dilakukan karena pengujian harus mengonfigurasi properti tingkat perangkat.

DeviceConfigurationOverride adalah API khusus pengujian yang memungkinkan Anda menyimulasikan berbagai konfigurasi perangkat secara lokal untuk konten @Composable yang sedang diuji.

Objek pendamping DeviceConfigurationOverride memiliki fungsi ekstensi berikut, yang menggantikan properti konfigurasi tingkat perangkat:

Untuk menerapkan penggantian tertentu, gabungkan konten yang sedang diuji dalam panggilan ke fungsi tingkat atas DeviceConfigurationOverride(), dengan meneruskan penggantian yang akan diterapkan sebagai parameter.

Misalnya, kode berikut menerapkan penggantian DeviceConfigurationOverride.ForcedSize() untuk mengubah kepadatan secara lokal, sehingga memaksa composable MyScreen dirender di jendela lanskap besar, meskipun perangkat yang menjalankan pengujian tidak mendukung ukuran jendela tersebut secara langsung:

composeTestRule.setContent {
    DeviceConfigurationOverride(
        DeviceConfigurationOverride.ForcedSize(DpSize(1280.dp, 800.dp))
    ) {
        MyScreen() // Will be rendered in the space for 1280dp by 800dp without clipping.
    }
}

Untuk menerapkan beberapa penggantian secara bersamaan, gunakan DeviceConfigurationOverride.then():

composeTestRule.setContent {
    DeviceConfigurationOverride(
        DeviceConfigurationOverride.FontScale(1.5f) then
            DeviceConfigurationOverride.FontWeightAdjustment(200)
    ) {
        Text(text = "text with increased scale and weight")
    }
}

Penanganan kegagalan kustom dalam pengujian

Men-debug pengujian UI sering kali memerlukan pemeriksaan status layar dan hierarki komposisi saat pernyataan gagal.

Compose menyediakan pipeline penanganan kegagalan native untuk menyederhanakan diagnostik. Anda dapat otomatis mengambil screenshot dan hierarki UI saat terjadi kegagalan, atau mendaftarkan pengendali kustom untuk meneruskan telemetri error ke alat eksternal.

Mengonfigurasi penanganan kegagalan

Untuk mengonfigurasi penanganan kegagalan, teruskan objek TestFailurePolicy ke ComposeUiTestConfig.

Mengambil artefak kegagalan bawaan

Untuk mengambil screenshot dan hierarki UI saat pengujian gagal, tetapkan properti screenshotCaptureMode dan uiHierarchyCaptureMode di TestFailurePolicy.

class MyComposeTest {
    private val customConfig = ComposeUiTestConfig(
        failurePolicy = TestFailurePolicy(
            screenshotCaptureMode = TestFailurePolicy.CaptureMode.Enabled,
            uiHierarchyCaptureMode = TestFailurePolicy.CaptureMode.Enabled
        )
    )

    @Test
    fun myFirstTest() = runComposeUiTest(config = customConfig) {
        // ...
    }
}

Menggunakan pengendali kegagalan kustom

Untuk menentukan perilaku kustom untuk kegagalan pengujian, tambahkan TestFailureHandler ke daftar failureHandlers. Setiap pengendali menerima objek FailureContext yang berisi error asli dan daftar artefak yang dihasilkan oleh pengendali pipeline sebelumnya.

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)

    // ...
}

Mengonfigurasi perekaman untuk seluruh suite pengujian

Anda dapat mengaktifkan pengambilan artefak kegagalan untuk seluruh suite pengujian dengan meneruskan argumen runner instrumentasi dalam file build.gradle modul Anda. Hal ini menghilangkan kebutuhan untuk memperbarui file pengujian individual.

// build.gradle.kts
android {
    defaultConfig {
        // ...
        testInstrumentationRunnerArguments["androidx.compose.ui.test.failure.isUiHierarchyCaptureEnabled"] = "true"
        testInstrumentationRunnerArguments["androidx.compose.ui.test.failure.isScreenshotCaptureEnabled"] = "true"
    }
}

Prioritas konfigurasi

Framework ini mengevaluasi argumen runner TestFailurePolicy lokal dan tingkat suite:

  • Jika Anda secara eksplisit menetapkan mode ke CaptureMode.Enabled/Disabled di failurePolicy pengujian, tindakan ini akan menggantikan argumen runner.
  • Jika Anda menetapkan mode ke CaptureMode.Unspecified (atau membiarkan failurePolicy sebagai null), framework akan kembali ke argumen runner.

Referensi Tambahan

  • Menguji aplikasi di Android: Halaman landing pengujian Android utama memberikan gambaran yang lebih luas tentang dasar-dasar dan teknik pengujian.
  • Dasar-dasar pengujian: Pelajari lebih lanjut konsep inti di balik pengujian aplikasi Android.
  • Pengujian lokal: Anda dapat menjalankan beberapa pengujian secara lokal, di workstation Anda sendiri.
  • Uji instrumentasi: Sebaiknya jalankan juga uji instrumentasi. Artinya, pengujian yang berjalan langsung di perangkat.
  • Continuous integration: Continuous integration memungkinkan Anda mengintegrasikan pengujian ke dalam pipeline deployment.
  • Menguji berbagai ukuran layar: Dengan banyaknya perangkat yang tersedia bagi pengguna, Anda harus menguji berbagai ukuran layar.
  • Espresso: Meskipun ditujukan untuk UI berbasis View, pengetahuan Espresso masih dapat membantu untuk beberapa aspek pengujian Compose.