ความสามารถในการแลกเปลี่ยนข้อมูล

Compose ผสานรวมกับเฟรมเวิร์กการทดสอบทั่วไป

ความสามารถในการทำงานร่วมกันกับ Espresso

ในแอปแบบผสม คุณจะเห็นคอมโพเนนต์ Compose ภายในลำดับชั้นการแสดงผลและมุมมองภายใน Composable ของ Compose (ผ่าน Composable AndroidView)

คุณไม่จำเป็นต้องทำตามขั้นตอนพิเศษใดๆ เพื่อจับคู่ทั้ง 2 ประเภท คุณจับคู่มุมมองกับ onView ของ Espresso และจับคู่อินเทอร์เฟซ Compose กับ 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()))
}

เพิ่มความหมายที่กำหนดขอบเขตมุมมองสำหรับการทดสอบความสามารถในการทำงานร่วมกันของ Compose

จำกัดขอบเขตการค้นหาใน Compose ให้เป็นมุมมองที่เฉพาะเจาะจง

เมื่อย้ายข้อมูล UI ที่ซับซ้อนไปยัง Compose คุณอาจพบองค์ประกอบ Compose ที่เหมือนกันซึ่งฝังอยู่ภายใน Android View แบบดั้งเดิมหลายรายการ เช่น ภายใน RecyclerView หรือ ViewPager ในสถานการณ์เหล่านี้ การค้นหา Compose มาตรฐาน เช่น onNodeWithText("Save") อาจไม่สำเร็จโดยมีข้อผิดพลาด "พบหลายโหนด"

แทนที่จะแก้ไขโค้ดเวอร์ชันที่ใช้งานจริงเพื่อแทรกแท็กทดสอบแบบไดนามิกเพื่อแยกแยะองค์ประกอบเหล่านี้ คุณสามารถกำหนดขอบเขตการทดสอบ Compose ไปยัง Android View ที่เฉพาะเจาะจงได้โดยตรง

ใช้ onRootWithViewInteraction API ในกฎการทดสอบ ฟังก์ชันนี้ยอมรับ ViewInteraction ของ Espresso ซึ่งช่วยให้คุณใช้ประโยชน์จาก Espresso เพื่อแยกมุมมองคอนเทนเนอร์ที่เฉพาะเจาะจงและดำเนินการโต้ตอบ Compose ภายในลำดับชั้นที่กำหนดขอบเขตนั้นโดยเฉพาะ

โต้ตอบกับรายการในลิสต์

หากต้องการโต้ตอบกับองค์ประกอบ Compose ภายในแถว RecyclerView ที่เฉพาะเจาะจง ให้ใช้ Espresso เพื่อค้นหาแถว แล้วกำหนดขอบเขตการโต้ตอบ Compose ไปยังแถวนั้น ซึ่งจะละเว้นองค์ประกอบ Compose ที่เหมือนกันในแถวอื่นๆ ทั้งหมด

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

แก้ไขความกำกวมใน ViewPager

เมื่อมีหลาย Fragment ที่มีเลย์เอาต์ Compose เหมือนกันอยู่ในหน่วยความจำพร้อมกัน คุณสามารถจำกัดขอบเขตการค้นหาให้อยู่ในรหัส View ระดับรูทของ Fragment ที่เฉพาะเจาะจงเพื่อป้องกันความกำกวมในการจับคู่

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

ความสามารถในการทำงานร่วมกันกับ UiAutomator

โดยค่าเริ่มต้น คอมโพสิเบิลจะเข้าถึงได้จาก UiAutomator ผ่านข้อบ่งชี้ที่สะดวกเท่านั้น (ข้อความที่แสดง คำอธิบายเนื้อหา ฯลฯ) หากต้องการเข้าถึง Composable ที่ใช้ Modifier.testTag คุณต้องเปิดใช้พร็อพเพอร์ตี้เชิงความหมาย testTagsAsResourceId สำหรับซับทรีของ Composable นั้นๆ การเปิดใช้ลักษณะการทำงานนี้มีประโยชน์สำหรับ Composable ที่ไม่มีแฮนเดิลที่ไม่ซ้ำกันอื่นๆ เช่น Composable ที่เลื่อนได้ (เช่น LazyColumn)

เปิดใช้พร็อพเพอร์ตี้เชิงความหมายเพียงครั้งเดียวในลำดับชั้น Composable เพื่อให้มั่นใจว่า Composable ที่ฝังทั้งหมดซึ่งมี Modifier.testTag จะเข้าถึงได้จาก 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
    }
}

คอมโพสิเบิลที่มี Modifier.testTag(tag) จะเข้าถึงได้ด้วยการใช้ By.res(resourceName) โดยใช้ tag เดียวกันกับ resourceName

val device = UiDevice.getInstance(getInstrumentation())

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

แหล่งข้อมูลเพิ่มเติม

  • ทดสอบแอปใน Android: หน้า Landing Page หลักสำหรับการทดสอบ Android จะแสดงมุมมองที่กว้างขึ้นเกี่ยวกับพื้นฐานและเทคนิคการทดสอบ
  • พื้นฐานของการทดสอบ: ดูข้อมูลเพิ่มเติมเกี่ยวกับแนวคิดหลักเบื้องหลังการทดสอบแอป Android
  • การทดสอบในเครื่อง: คุณสามารถทำการทดสอบบางอย่างในเครื่องบนเวิร์กสเตชันของคุณเองได้
  • การทดสอบการวัดคุม: คุณควรเรียกใช้การทดสอบการวัดคุมด้วย ซึ่งก็คือการทดสอบที่ทำงานในอุปกรณ์โดยตรง
  • การรวมอย่างต่อเนื่อง: การรวมอย่างต่อเนื่องช่วยให้คุณผสานรวมการทดสอบเข้ากับไปป์ไลน์การติดตั้งใช้งานได้
  • ทดสอบหน้าจอขนาดต่างๆ: เนื่องจากผู้ใช้มีอุปกรณ์หลากหลายประเภท คุณจึงควรทดสอบหน้าจอขนาดต่างๆ
  • Espresso: แม้ว่า Espresso จะมีไว้สำหรับ UI แบบอิงตามมุมมอง แต่ความรู้เกี่ยวกับ Espresso ก็ยังคงเป็นประโยชน์สำหรับการทดสอบ Compose ในบางแง่มุม