Interoperabilitas

Compose terintegrasi dengan framework pengujian umum.

Interoperabilitas dengan Espresso

Dalam aplikasi hybrid, Anda dapat menemukan komponen Compose di dalam hierarki tampilan dan tampilan di dalam composable Compose (melalui composable AndroidView).

Tidak memerlukan langkah khusus untuk mencocokkan salah satu jenisnya. Anda mencocokkan tampilan dengan onView Espresso, dan elemen Compose dengan ComposeTestRule.

@Test
fun androidViewInteropTest() {
    // Check the initial state of a TextView that depends on a Compose state.
    Espresso.onView(withText("Hello Views")).check(matches(isDisplayed()))
    // Click on the Compose button that changes the state.
    composeTestRule.onNodeWithText("Click here").performClick()
    // Check the new value.
    Espresso.onView(withText("Hello Compose")).check(matches(isDisplayed()))
}

Menambahkan semantik cakupan View untuk pengujian interop Compose

Membatasi penelusuran Compose ke View tertentu

Saat memigrasikan UI yang kompleks ke Compose, Anda mungkin menemukan elemen Compose identik yang bertingkat di dalam beberapa View Android tradisional—seperti dalam RecyclerView atau ViewPager. Dalam skenario ini, penelusuran Compose standar seperti onNodeWithText("Save") mungkin gagal dengan error "Beberapa node ditemukan".

Daripada mengubah kode produksi untuk memasukkan tag pengujian dinamis guna membedakan elemen-elemen ini, Anda dapat mencakup pengujian Compose secara langsung ke View Android tertentu.

Gunakan onRootWithViewInteraction API pada aturan pengujian Anda. Fungsi ini menerima ViewInteraction Espresso, sehingga Anda dapat memanfaatkan Espresso untuk mengisolasi View container tertentu dan melakukan interaksi Compose secara eksklusif dalam hierarki yang tercakup tersebut.

Berinteraksi dengan item daftar

Jika Anda perlu berinteraksi dengan elemen Compose di dalam baris RecyclerView tertentu, gunakan Espresso untuk menemukan baris, lalu cakup interaksi Compose Anda ke baris tersebut. Tindakan ini akan mengabaikan elemen Compose yang identik di semua baris lainnya.

@Test
fun testComposeButtonInsideRecyclerViewItem() = runComposeUiTest {
    // Scroll to the desired position using Espresso
    Espresso.onView(withId(recyclerViewId))
        .perform(RecyclerViewActions.scrollToPosition<MyViewHolder>(3))

    // Define an Espresso ViewInteraction that uniquely identifies the row
    val rowView = Espresso.onView(
        allOf(
            withId(rootViewId),
            hasDescendant(withText("Item #3"))
        )
    )

    // Scope the Compose search strictly to that specific row View
    onRootWithViewInteraction(rowView)
        .onNode(hasText("Like"))
        .performClick()
}

Menyelesaikan ambiguitas di ViewPager

Jika beberapa fragmen dengan tata letak Compose yang identik berada dalam memori secara bersamaan, Anda dapat mencakup penelusuran ke ID Tampilan root fragmen tertentu untuk mencegah ambiguitas pencocokan.

@Test
fun testComposeButtonInsideViewPagerItem() = runComposeUiTest {
    // Swipe to the desired page using Espresso
    Espresso.onView(withId(viewPagerViewId)).perform(swipeLeft())

    // Identify the specific container view using Espresso
    val fragmentB = Espresso.onView(withId(fragmentRootViewId))

    // The generic text "Save" is now unique within this view scope
    onRootWithViewInteraction(fragmentB)
        .onNode(hasText("Save"))
        .assertIsDisplayed()
}

Interoperabilitas dengan UiAutomator

Secara default, composable dapat diakses dari UiAutomator hanya dengan deskripsi yang praktis (teks yang ditampilkan, deskripsi konten, dll.). Jika ingin mengakses semua composable yang menggunakan Modifier.testTag, Anda harus mengaktifkan properti semantik testTagsAsResourceId untuk subhierarki composable tertentu. Mengaktifkan perilaku ini berguna untuk composable yang tidak memiliki handle unik lainnya, seperti composable yang dapat di-scroll (misalnya, LazyColumn).

Aktifkan properti semantik hanya sekali di hierarki composable untuk memastikan semua composable bertingkat dengan Modifier.testTag dapat diakses dari UiAutomator.

Scaffold(
    // Enables for all composables in the hierarchy.
    modifier = Modifier.semantics {
        testTagsAsResourceId = true
    }
){
    // Modifier.testTag is accessible from UiAutomator for composables nested here.
    LazyColumn(
        modifier = Modifier.testTag("myLazyColumn")
    ){
        // Content
    }
}

Setiap composable dengan Modifier.testTag(tag) dapat diakses dengan penggunaan By.res(resourceName) menggunakan tag yang sama seperti resourceName.

val device = UiDevice.getInstance(getInstrumentation())

val lazyColumn: UiObject2 = device.findObject(By.res("myLazyColumn"))
// Some interaction with the lazyColumn.

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.