หัวข้อนี้อธิบายวิธีรวม API ที่ได้จากเฟรมเวิร์กในการทดสอบ ที่ใช้ประเมินพฤติกรรมของแต่ละส่วนย่อย
Fragment จะทำหน้าที่เป็นคอนเทนเนอร์ที่ใช้ซ้ำได้ภายในแอปของคุณ ซึ่งช่วยให้คุณทำสิ่งต่อไปนี้ได้ นำเสนอเลย์เอาต์อินเทอร์เฟซผู้ใช้ชุดเดียวกันในหลายๆ กิจกรรมและ และการกำหนดค่าเลย์เอาต์ทั้งหมด เนื่องจากส่วนย่อยมีความอเนกประสงค์ จึงมีความสำคัญ เพื่อมอบประสบการณ์การใช้งานที่สม่ำเสมอและประหยัดทรัพยากร ข้อควรทราบ
- ส่วนย่อยของคุณไม่ควรขึ้นอยู่กับกิจกรรมหลักที่เจาะจงหรือ ส่วนย่อย
- คุณไม่ควรสร้างลำดับชั้นการดูของส่วนย่อยนอกเสียจากว่าส่วนย่อย แสดงต่อผู้ใช้
ในการช่วยกำหนดเงื่อนไขสำหรับการทดสอบเหล่านี้ AndroidX ไลบรารี fragment-testing ให้บริการ FragmentScenario เพื่อสร้างส่วนย่อยและเปลี่ยนส่วน Lifecycle.State
การประกาศทรัพยากร Dependency
หากต้องการใช้ FragmentScenario ให้กำหนดอาร์ติแฟกต์ fragment-testing-manifest ใน ไฟล์ build.gradle ของแอปที่ใช้ debugImplementation และอาร์ติแฟกต์ fragment-testing ที่ใช้ androidTestImplementation ตามที่แสดงใน ตัวอย่างต่อไปนี้
ดึงดูด
dependencies { def fragment_version = "1.8.9" debugImplementation "androidx.fragment:fragment-testing-manifest:$fragment_version" androidTestImplementation "androidx.fragment:fragment-testing:$fragment_version" }
Kotlin
dependencies { val fragment_version = "1.8.9" debugImplementation("androidx.fragment:fragment-testing-manifest:$fragment_version") androidTestImplementation("androidx.fragment:fragment-testing:$fragment_version") }
ตัวอย่างการทดสอบในหน้านี้ใช้การยืนยันจาก Espresso และ ไลบรารี Truth สำหรับข้อมูลเกี่ยวกับ ไลบรารีการทดสอบและการยืนยันอื่นๆ ที่มีอยู่ โปรดดู ตั้งค่าโปรเจ็กต์สำหรับ AndroidX Test
สร้างส่วนย่อย
FragmentScenario มีเมธอดต่อไปนี้สำหรับการเปิดใช้ Fragment ในการทดสอบ:
launchInContainer()เพื่อทดสอบอินเทอร์เฟซผู้ใช้ของ FragmentFragmentScenarioแนบ ไปยังตัวควบคุมมุมมองรูทของกิจกรรม กิจกรรมนี้มีกิจกรรมอยู่ หรือว่างเปล่าlaunch()สำหรับการทดสอบโดยไม่มีอินเทอร์เฟซผู้ใช้ของ FragmentFragmentScenarioแนบส่วนย่อยประเภทนี้กับกิจกรรมเปล่าซึ่งไม่ มีมุมมองรูท
หลังจากเปิดใช้งานหนึ่งในประเภทส่วนย่อยเหล่านี้ FragmentScenario จะขับเคลื่อน ส่วนย่อยภายใต้การทดสอบเป็นสถานะที่ระบุ โดยค่าเริ่มต้น สถานะนี้คือ RESUMED แต่คุณสามารถลบล้างได้ด้วยอาร์กิวเมนต์ initialState รัฐRESUMED บ่งบอกว่าส่วนย่อยกำลังทำงานและแสดงต่อผู้ใช้ คุณสามารถประเมิน ข้อมูลเกี่ยวกับองค์ประกอบ UI โดยใช้ Espresso UI การทดสอบ
ตัวอย่างโค้ดต่อไปนี้แสดงวิธีเปิดใช้งานส่วนย่อยโดยใช้แต่ละวิธี
ตัวอย่าง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) ... } } ตัวอย่าง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) ... } } ระบุทรัพยากร Dependency
หาก Fragment มีทรัพยากร Dependency คุณระบุเวอร์ชันทดสอบของ ทรัพยากร Dependency เหล่านี้ด้วยการระบุ FragmentFactory ที่กำหนดเองให้กับเมธอด launchInContainer() หรือ launch() เมธอด
@RunWith(AndroidJUnit4::class) class MyTestSuite { @Test fun testEventFragment() { val someDependency = TestDependency() launchFragmentInContainer { EventFragment(someDependency) } ... } } หากต้องการข้อมูลเพิ่มเติมเกี่ยวกับการใช้ FragmentFactory เพื่อให้ การอ้างอิงกับส่วนย่อย โปรดดู ตัวจัดการส่วนย่อย
ขับเคลื่อนส่วนย่อยไปยังสถานะใหม่
ในการทดสอบ UI ของแอป ตามปกติแล้วการเรียกใช้ Fragment ก็เพียงพอแล้ว อยู่ระหว่างทดสอบ และเริ่มทดสอบจากสถานะ RESUMED แบบละเอียด อย่างไรก็ดี คุณอาจประเมินลักษณะการทำงานของส่วนย่อยด้วย เมื่อเปลี่ยนจากวงจรหนึ่งไปเป็นอีกวงจรหนึ่ง คุณสามารถระบุ สถานะเริ่มต้นโดยการส่งอาร์กิวเมนต์ initialState ไปยัง launchFragment*() ฟังก์ชัน
หากต้องการขับเคลื่อนส่วนย่อยไปยังสถานะวงจรอื่น ให้เรียกใช้ moveToState() เมธอดนี้รองรับสถานะต่อไปนี้เป็นอาร์กิวเมนต์: CREATED, STARTED, RESUMED และ DESTROYED วิธีนี้จำลองสถานการณ์ ส่วนที่ส่วนย่อยหรือกิจกรรมที่มีส่วนย่อยเปลี่ยนแปลง ด้วยเหตุผลใดก็ตาม
ตัวอย่างต่อไปนี้จะเปิดส่วนย่อยการทดสอบในสถานะ INITIALIZED และ จากนั้นย้ายไปยังสถานะ 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. ... } } สร้างส่วนย่อยใหม่
หากแอปของคุณกำลังทำงานบนอุปกรณ์ที่มีทรัพยากรต่ำ ระบบจะ อาจทำลายกิจกรรมที่มีส่วนย่อยของคุณ สถานการณ์นี้ กำหนดให้แอปสร้างส่วนย่อยอีกครั้งเมื่อผู้ใช้ย้อนกลับ หากต้องการจำลองสถานการณ์นี้ โปรดโทรหา recreate():
@RunWith(AndroidJUnit4::class) class MyTestSuite { @Test fun testEventFragment() { val scenario = launchFragmentInContainer<EventFragment>() scenario.recreate() ... } } FragmentScenario.recreate() ทำลายส่วนย่อยและโฮสต์ของส่วนนั้น แล้วจึงสร้างใหม่ เมื่อ คลาส FragmentScenario จะสร้างส่วนย่อยอีกครั้งภายใต้การทดสอบ ซึ่งก็คือส่วนย่อย จะกลับสู่สถานะของวงจรการใช้งานก่อนที่จะถูกทำลาย
การดำเนินการกับส่วนย่อยของ UI
หากต้องการทริกเกอร์การทำงานของ UI ในส่วนย่อยของคุณภายใต้การทดสอบ ให้ใช้ ตัวจับคู่มุมมองเอสเพรสโซ โต้ตอบกับองค์ประกอบในมุมมองของคุณ
@RunWith(AndroidJUnit4::class) class MyTestSuite { @Test fun testEventFragment() { val scenario = launchFragmentInContainer<EventFragment>() onView(withId(R.id.refresh)).perform(click()) // Assert some expected behavior ... } } ถ้าคุณต้องการเรียกเมธอดในส่วนนั้น เช่น การตอบกลับ ไปยังตัวเลือกในเมนูตัวเลือก คุณสามารถทำได้อย่างปลอดภัยโดย อ้างอิงไปยังส่วนย่อยโดยใช้ FragmentScenario.onFragment() และการผ่านใน FragmentAction:
@RunWith(AndroidJUnit4::class) class MyTestSuite { @Test fun testEventFragment() { val scenario = launchFragmentInContainer<EventFragment>() scenario.onFragment { fragment -> fragment.myInstanceMethod() } } } ทดสอบการทำงานของกล่องโต้ตอบ
FragmentScenario ยังรองรับการทดสอบ ส่วนย่อยของกล่องโต้ตอบ แม้ว่าส่วนย่อยของกล่องโต้ตอบ มีองค์ประกอบ UI การจัดวางจะปรากฏในหน้าต่างแยกต่างหาก มากกว่าในตัวกิจกรรมเอง ด้วยเหตุนี้ ให้ใช้ FragmentScenario.launch() เพื่อทดสอบส่วนย่อยของกล่องโต้ตอบ
ตัวอย่างต่อไปนี้จะทดสอบกระบวนการปิดกล่องโต้ตอบ
@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()) } }