คุณสามารถทดสอบแอป Compose ด้วยแนวทางและรูปแบบที่ได้รับการยอมรับเป็นอย่างดี
ทดสอบแบบแยกต่างหาก
ComposeTestRule ช่วยให้คุณเริ่มกิจกรรมที่แสดง Composable ใดก็ได้ ไม่ว่าจะเป็นแอปพลิเคชันแบบเต็ม หน้าจอเดียว หรือองค์ประกอบเล็กๆ นอกจากนี้ คุณควรตรวจสอบว่าคอมโพสิเบิลได้รับการแคปซูลอย่างถูกต้องและทำงานอย่างเป็นอิสระ ซึ่งจะช่วยให้การทดสอบ UI ง่ายขึ้นและมุ่งเน้นมากขึ้น
แต่ไม่ได้หมายความว่าคุณควรสร้างเฉพาะการทดสอบ UI ระดับหน่วย การทดสอบ UI ที่ครอบคลุมส่วนต่างๆ ของ UI มากขึ้นก็มีความสำคัญมากเช่นกัน
เข้าถึงกิจกรรมและแหล่งข้อมูลหลังจากตั้งค่าเนื้อหาของคุณเอง
บ่อยครั้งที่คุณต้องตั้งค่าเนื้อหาที่อยู่ระหว่างการทดสอบโดยใช้ composeTestRule.setContent และคุณยังต้องเข้าถึงทรัพยากรกิจกรรมด้วย เช่น เพื่อยืนยันว่าข้อความที่แสดงตรงกับทรัพยากรสตริง อย่างไรก็ตาม คุณไม่สามารถเรียก setContent ในกฎที่สร้างด้วย createAndroidComposeRule() หากกิจกรรมเรียกใช้อยู่แล้ว
รูปแบบทั่วไปในการดำเนินการนี้คือการสร้าง AndroidComposeTestRule โดยใช้กิจกรรมที่ว่างเปล่า เช่น 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()
}
}
โปรดทราบว่าคุณต้องเพิ่ม ComponentActivity ลงในไฟล์ AndroidManifest.xml ของแอป เปิดใช้โดยเพิ่มการอ้างอิงนี้ลงในโมดูล
debugImplementation("androidx.compose.ui:ui-test-manifest:$compose_version")
พร็อพเพอร์ตี้ความหมายที่กำหนดเอง
คุณสามารถสร้างพร็อพเพอร์ตี้ความหมายที่กำหนดเองเพื่อแสดงข้อมูลต่อการทดสอบได้
โดยให้กำหนด SemanticsPropertyKey ใหม่และทำให้พร้อมใช้งานโดยใช้ SemanticsPropertyReceiver
// Creates a semantics property of type Long.
val PickedDateKey = SemanticsPropertyKey<Long>("PickedDate")
var SemanticsPropertyReceiver.pickedDate by PickedDateKey
ตอนนี้ให้ใช้พร็อพเพอร์ตี้นั้นในตัวแก้ไข semantics ดังนี้
val datePickerValue by remember { mutableStateOf(0L) }
MyCustomDatePicker(
modifier = Modifier.semantics { pickedDate = datePickerValue }
)
จากการทดสอบ ให้ใช้ SemanticsMatcher.expectValue เพื่อยืนยันค่าของพร็อพเพอร์ตี้
composeTestRule
.onNode(SemanticsMatcher.expectValue(PickedDateKey, 1445378400)) // 2015-10-21
.assertExists()
ยืนยันการคืนค่าสถานะ
ตรวจสอบว่าสถานะขององค์ประกอบ Compose ได้รับการกู้คืนอย่างถูกต้องเมื่อมีการสร้างกิจกรรมหรือกระบวนการขึ้นมาใหม่ ทำการตรวจสอบดังกล่าวโดยไม่ต้องอาศัยการสร้างกิจกรรมใหม่ด้วยคลาส StateRestorationTester
คลาสนี้ช่วยให้คุณจำลองการสร้าง Composable ขึ้นมาใหม่ได้ ซึ่งมีประโยชน์อย่างยิ่งในการยืนยันการติดตั้งใช้งาน 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.
}
}
ทดสอบการกำหนดค่าอุปกรณ์แบบต่างๆ
แอป Android ต้องปรับให้เข้ากับสภาวะต่างๆ ที่เปลี่ยนแปลงไป เช่น ขนาดหน้าต่าง ภาษา ขนาดแบบอักษร ธีมมืดและสว่าง และอื่นๆ เงื่อนไขเหล่านี้ส่วนใหญ่ได้มาจากค่าระดับอุปกรณ์ที่ผู้ใช้ควบคุมและแสดงด้วยอินสแตนซ์ Configuration ปัจจุบัน การทดสอบการกำหนดค่าต่างๆ ในการทดสอบโดยตรงเป็นเรื่องยาก เนื่องจากการทดสอบต้องกำหนดค่าพร็อพเพอร์ตี้ระดับอุปกรณ์
DeviceConfigurationOverride เป็น API สำหรับการทดสอบเท่านั้นที่ช่วยให้คุณจำลองการกำหนดค่าอุปกรณ์ต่างๆ ในรูปแบบที่แปลแล้วสำหรับเนื้อหา @Composable ที่อยู่ระหว่างการทดสอบ
ออบเจ็กต์ที่ใช้ร่วมกันของ DeviceConfigurationOverride มีฟังก์ชันส่วนขยายต่อไปนี้ ซึ่งจะลบล้างพร็อพเพอร์ตี้การกำหนดค่าระดับอุปกรณ์
DeviceConfigurationOverride.DarkMode(): ลบล้างระบบเป็นธีมมืดหรือธีมสว่างDeviceConfigurationOverride.FontScale(): ลบล้างขนาดแบบอักษรของระบบDeviceConfigurationOverride.FontWeightAdjustment(): ลบล้างการปรับน้ำหนักแบบอักษรของระบบDeviceConfigurationOverride.ForcedSize(): บังคับให้มีพื้นที่ว่างตามจำนวนที่ระบุไม่ว่าอุปกรณ์จะมีขนาดเท่าใดก็ตามDeviceConfigurationOverride.LayoutDirection(): ลบล้างทิศทางของเลย์เอาต์ (จากซ้ายไปขวาหรือจากขวาไปซ้าย)DeviceConfigurationOverride.Locales(): ลบล้างภาษาDeviceConfigurationOverride.RoundScreen(): ลบล้างหากหน้าจอเป็นทรงกลม
หากต้องการใช้การลบล้างที่เฉพาะเจาะจง ให้รวมเนื้อหาที่ทดสอบไว้ในการเรียกใช้ฟังก์ชันระดับบนสุด DeviceConfigurationOverride() โดยส่งการลบล้างที่จะใช้เป็นพารามิเตอร์
ตัวอย่างเช่น โค้ดต่อไปนี้ใช้การลบล้าง DeviceConfigurationOverride.ForcedSize() เพื่อเปลี่ยนความหนาแน่นในเครื่อง โดยบังคับให้ Composable MyScreen แสดงผลในหน้าต่างแนวนอนขนาดใหญ่ แม้ว่าอุปกรณ์ที่ทำการทดสอบจะไม่รองรับขนาดหน้าต่างนั้นโดยตรงก็ตาม
composeTestRule.setContent { DeviceConfigurationOverride( DeviceConfigurationOverride.ForcedSize(DpSize(1280.dp, 800.dp)) ) { MyScreen() // Will be rendered in the space for 1280dp by 800dp without clipping. } }
หากต้องการใช้การลบล้างหลายรายการร่วมกัน ให้ใช้ DeviceConfigurationOverride.then() ดังนี้
composeTestRule.setContent { DeviceConfigurationOverride( DeviceConfigurationOverride.FontScale(1.5f) then DeviceConfigurationOverride.FontWeightAdjustment(200) ) { Text(text = "text with increased scale and weight") } }
การจัดการความล้มเหลวที่กำหนดเองในการทดสอบ
การแก้ไขข้อบกพร่องของการทดสอบ UI มักจะต้องตรวจสอบสถานะหน้าจอและลำดับชั้นขององค์ประกอบเมื่อการยืนยันไม่สำเร็จ
Compose มีไปป์ไลน์การจัดการความล้มเหลวแบบเนทีฟเพื่อปรับปรุงการวินิจฉัยให้มีประสิทธิภาพยิ่งขึ้น คุณสามารถจับภาพหน้าจอและลำดับชั้น UI โดยอัตโนมัติเมื่อเกิดความล้มเหลว หรือลงทะเบียนเครื่องมือจัดการที่กำหนดเองเพื่อส่งต่อการวัดและส่งข้อมูลทางไกลเกี่ยวกับข้อขัดข้องไปยังเครื่องมือภายนอก
กำหนดค่าการจัดการความล้มเหลว
หากต้องการกำหนดค่าการจัดการความล้มเหลว ให้ส่งออบเจ็กต์ TestFailurePolicy ไปยัง ComposeUiTestConfig
บันทึกอาร์ติแฟกต์ความล้มเหลวในตัว
หากต้องการจับภาพหน้าจอและลำดับชั้น UI เมื่อการทดสอบไม่สำเร็จ ให้ตั้งค่าพร็อพเพอร์ตี้ screenshotCaptureMode และ uiHierarchyCaptureMode ใน TestFailurePolicy
class MyComposeTest { private val customConfig = ComposeUiTestConfig( failurePolicy = TestFailurePolicy( screenshotCaptureMode = TestFailurePolicy.CaptureMode.Enabled, uiHierarchyCaptureMode = TestFailurePolicy.CaptureMode.Enabled ) ) @Test fun myFirstTest() = runComposeUiTest(config = customConfig) { // ... } }
ใช้เครื่องมือจัดการความล้มเหลวที่กำหนดเอง
หากต้องการกำหนดลักษณะการทำงานที่กำหนดเองสำหรับการทดสอบที่ล้มเหลว ให้เพิ่ม TestFailureHandler ลงในรายการ failureHandlers เครื่องจัดการแต่ละรายการจะได้รับออบเจ็กต์ FailureContext ที่มีข้อผิดพลาดเดิมและรายการอาร์ติแฟกต์ที่สร้างขึ้นโดยเครื่องจัดการไปป์ไลน์ก่อนหน้า
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) // ... }
กำหนดค่าการจับภาพสำหรับชุดโปรแกรมทดสอบทั้งหมด
คุณสามารถเปิดใช้การบันทึกอาร์ติแฟกต์ที่ล้มเหลวสำหรับชุดโปรแกรมทดสอบทั้งหมดได้โดยส่งอาร์กิวเมนต์ของตัวรันการวัดคุมในไฟล์ build.gradle ของโมดูล ซึ่งจะช่วยลดความจำเป็นในการอัปเดตไฟล์ทดสอบแต่ละไฟล์
// build.gradle.kts
android {
defaultConfig {
// ...
testInstrumentationRunnerArguments["androidx.compose.ui.test.failure.isUiHierarchyCaptureEnabled"] = "true"
testInstrumentationRunnerArguments["androidx.compose.ui.test.failure.isScreenshotCaptureEnabled"] = "true"
}
}
ลำดับความสำคัญของการกำหนดค่า
เฟรมเวิร์กจะประเมินทั้งอาร์กิวเมนต์ของ Runner ระดับ TestFailurePolicy ในเครื่องและระดับชุดทดสอบ ดังนี้
- หากคุณตั้งค่าโหมดเป็น
CaptureMode.Enabled/Disabledอย่างชัดแจ้งในfailurePolicyทดสอบ การตั้งค่านี้จะลบล้างอาร์กิวเมนต์ Runner - หากคุณตั้งค่าโหมดเป็น
CaptureMode.Unspecified(หรือปล่อยfailurePolicyไว้เป็นnull) เฟรมเวิร์กจะกลับไปใช้อาร์กิวเมนต์ Runner
แหล่งข้อมูลเพิ่มเติม
- ทดสอบแอปใน Android: หน้า Landing Page หลักสำหรับการทดสอบ Android จะแสดงมุมมองที่กว้างขึ้นเกี่ยวกับพื้นฐานและเทคนิคการทดสอบ
- พื้นฐานของการทดสอบ: ดูข้อมูลเพิ่มเติมเกี่ยวกับแนวคิดหลักเบื้องหลังการทดสอบแอป Android
- การทดสอบในเครื่อง: คุณสามารถทำการทดสอบบางอย่างในเครื่องบนเวิร์กสเตชันของคุณเองได้
- การทดสอบการวัดคุม: คุณควรเรียกใช้การทดสอบการวัดคุมด้วย ซึ่งก็คือการทดสอบที่ทำงานในอุปกรณ์โดยตรง
- การรวมอย่างต่อเนื่อง: การรวมอย่างต่อเนื่องช่วยให้คุณผสานรวมการทดสอบเข้ากับไปป์ไลน์การติดตั้งใช้งานได้
- ทดสอบหน้าจอขนาดต่างๆ: เนื่องจากผู้ใช้มีอุปกรณ์หลากหลายประเภท คุณจึงควรทดสอบหน้าจอขนาดต่างๆ
- Espresso: แม้ว่า Espresso จะมีไว้สำหรับ UI แบบอิงตามมุมมอง แต่ความรู้เกี่ยวกับ Espresso ก็ยังคงเป็นประโยชน์สำหรับการทดสอบ Compose ในบางแง่มุม