Espresso มีกลไกสำหรับเลื่อนหรือดำเนินการกับรายการใดรายการหนึ่ง ซึ่งได้แก่ มุมมองอะแดปเตอร์และมุมมองนักรีไซเคิล
เมื่อจัดการกับรายการ โดยเฉพาะรายการที่สร้างด้วย RecyclerView
หรือ
AdapterView
มุมมองที่คุณสนใจอาจไม่ได้เปิด
บนหน้าจอเพราะมีเด็กเพียงไม่กี่คนเท่านั้นที่แสดงและ
เป็นการรีไซเคิลขณะที่คุณเลื่อน ใช้เมธอด scrollTo()
ไม่ได้ในกรณีนี้
เนื่องจากจำเป็นต้องมีข้อมูลพร็อพเพอร์ตี้อยู่แล้ว
โต้ตอบกับรายการมุมมองรายการของอะแดปเตอร์
แทนที่จะใช้เมธอด onView()
ให้เริ่มการค้นหาด้วย onData()
และ
ระบุตัวจับคู่กับข้อมูลที่สนับสนุนข้อมูลพร็อพเพอร์ตี้ที่คุณต้องการจับคู่
เอสเพรสโซจะทำงานทั้งหมดเพื่อค้นหาแถวในออบเจ็กต์ Adapter
และ
ซึ่งทำให้รายการปรากฏในวิวพอร์ต
จับคู่ข้อมูลโดยใช้ตัวจับคู่มุมมองที่กำหนดเอง
กิจกรรมด้านล่างมี ListView
ซึ่งได้รับการสนับสนุนโดย SimpleAdapter
ที่เก็บข้อมูลสำหรับแต่ละแถวในออบเจ็กต์ Map<String, Object>
แต่ละแผนที่มี 2 รายการ ได้แก่ คีย์ "STR"
ที่มีสตริง เช่น
"item: x"
และคีย์ "LEN"
ที่มี Integer
ซึ่งแสดงถึง
ความยาวของเนื้อหา เช่น
{"STR" : "item: 0", "LEN": 7}
โค้ดสําหรับการคลิกแถวที่มี "item: 50" ซึ่งมีลักษณะดังนี้
Kotlin
onData(allOf(`is`(instanceOf(Map::class.java)), hasEntry(equalTo("STR"), `is`("item: 50")))).perform(click())
Java
onData(allOf(is(instanceOf(Map.class)), hasEntry(equalTo("STR"), is("item: 50")))) .perform(click());
โปรดทราบว่า Espresso เลื่อนดูรายการโดยอัตโนมัติตามที่ต้องการ
มาแยก Matcher<Object>
ภายใน onData()
กัน
is(instanceOf(Map.class))
จะจำกัดการค้นหาให้แสดงเฉพาะรายการ
AdapterView
ซึ่งได้รับการสนับสนุนโดยออบเจ็กต์ Map
ในกรณีของเรา ข้อความค้นหาด้านนี้ตรงกับแถวของมุมมองรายการทุกแถว แต่เรา คลิกรายการหนึ่งๆ โดยเฉพาะ เราจึงจำกัดการค้นหาให้แคบลงด้วยข้อมูลต่อไปนี้
Kotlin
hasEntry(equalTo("STR"), `is`("item: 50"))
Java
hasEntry(equalTo("STR"), is("item: 50"))
Matcher<String, Object>
นี้จะตรงกับแผนที่ใดๆ ที่มีรายการที่มี
คีย์ "STR"
และค่า "item: 50"
เพราะโค้ดที่ใช้ค้นหา
และเราต้องการนำมาใช้ใหม่ในสถานที่อื่นๆ ลองเขียนบรรทัดที่กำหนดเอง
ตัวจับคู่ withItemContent
สำหรับกรณีนี้:
Kotlin
return object : BoundedMatcher<Object, Map>(Map::class.java) { override fun matchesSafely(map: Map): Boolean { return hasEntry(equalTo("STR"), itemTextMatcher).matches(map) } override fun describeTo(description: Description) { description.appendText("with item content: ") itemTextMatcher.describeTo(description) } }
Java
return new BoundedMatcher<Object, Map>(Map.class) { @Override public boolean matchesSafely(Map map) { return hasEntry(equalTo("STR"), itemTextMatcher).matches(map); } @Override public void describeTo(Description description) { description.appendText("with item content: "); itemTextMatcher.describeTo(description); } };
คุณใช้ BoundedMatcher
เป็นฐานเนื่องจากเพื่อจับคู่เฉพาะวัตถุประเภท
Map
ลบล้างเมธอด matchesSafely()
โดยใส่ตัวจับคู่ที่พบ
ก่อนหน้านี้ และจับคู่กับ Matcher<String>
ที่คุณสามารถส่งผ่าน
อาร์กิวเมนต์ การดำเนินการนี้จะช่วยให้คุณโทรหา withItemContent(equalTo("foo"))
ได้ สำหรับรหัส
มีความกระชับ คุณสามารถสร้างตัวจับคู่อื่นที่เรียก equalTo()
และ
ยอมรับออบเจ็กต์ String
:
Kotlin
fun withItemContent(expectedText: String): Matcher<Object> { checkNotNull(expectedText) return withItemContent(equalTo(expectedText)) }
Java
public static Matcher<Object> withItemContent(String expectedText) { checkNotNull(expectedText); return withItemContent(equalTo(expectedText)); }
ตอนนี้โค้ดสำหรับคลิกรายการนั้นสามารถทำได้ง่าย:
Kotlin
onData(withItemContent("item: 50")).perform(click())
Java
onData(withItemContent("item: 50")).perform(click());
สำหรับโค้ดทั้งหมดของการทดสอบนี้ โปรดดูที่เมธอด testClickOnItem50()
ภายใน
AdapterViewTest
ชั้นเรียนและ
LongListMatchers
ที่กำหนดเองนี้
ตัวจับคู่ใน GitHub
ตรงกับมุมมองย่อยที่เจาะจง
ตัวอย่างด้านบนจะส่งออกการคลิกตรงกลางแถวทั้งแถวของ ListView
แต่หากต้องการดำเนินการกับระดับย่อยที่เจาะจง ตัวอย่างเช่น เรา
ต้องการคลิกคอลัมน์ที่ 2 ของแถว LongListActivity
ซึ่งจะแสดง String.length ของเนื้อหาในคอลัมน์แรก:
เพียงเพิ่มข้อกำหนด onChildView()
ลงในการใช้งาน
DataInteraction
:
Kotlin
onData(withItemContent("item: 60")) .onChildView(withId(R.id.item_size)) .perform(click())
Java
onData(withItemContent("item: 60")) .onChildView(withId(R.id.item_size)) .perform(click());
โต้ตอบกับรายการในมุมมองของผู้รีไซเคิล
ออบเจ็กต์ RecyclerView
รายการทำงานแตกต่างจากออบเจ็กต์ AdapterView
รายการ ดังนั้น
ไม่สามารถใช้ onData()
เพื่อโต้ตอบกับรายชื่อติดต่อได้
ในการโต้ตอบกับ RecyclerViews โดยใช้ Espresso คุณสามารถใช้
แพ็กเกจ espresso-contrib
ซึ่งมีคอลเล็กชัน
RecyclerViewActions
ที่ใช้เลื่อนไปยังตำแหน่งหรือดำเนินการกับรายการต่างๆ ได้
scrollTo()
- เลื่อนไปที่มุมมองที่ตรงกัน หากมีscrollToHolder()
- เลื่อนไปที่ตัวยึดตำแหน่งการดูที่ตรงกัน (หากมี)scrollToPosition()
- เลื่อนไปยังตำแหน่งที่ต้องการactionOnHolderItem()
- ดำเนินการดูกับตัวยึดตำแหน่งการดูที่ตรงกันactionOnItem()
- ดำเนินการดูในข้อมูลพร็อพเพอร์ตี้ที่ตรงกันactionOnItemAtPosition()
- ทำ ViewAction บนข้อมูลพร็อพเพอร์ตี้ที่ตำแหน่งที่เฉพาะเจาะจง
ข้อมูลต่อไปนี้จะแสดงตัวอย่างบางส่วนจาก RecyclerViewSample ตัวอย่าง:
Kotlin
@Test(expected = PerformException::class) fun itemWithText_doesNotExist() { // Attempt to scroll to an item that contains the special text. onView(ViewMatchers.withId(R.id.recyclerView)) .perform( // scrollTo will fail the test if no item matches. RecyclerViewActions.scrollTo( hasDescendant(withText("not in the list")) ) ) }
Java
@Test(expected = PerformException.class) public void itemWithText_doesNotExist() { // Attempt to scroll to an item that contains the special text. onView(ViewMatchers.withId(R.id.recyclerView)) // scrollTo will fail the test if no item matches. .perform(RecyclerViewActions.scrollTo( hasDescendant(withText("not in the list")) )); }
Kotlin
@Test fun scrollToItemBelowFold_checkItsText() { // First, scroll to the position that needs to be matched and click on it. onView(ViewMatchers.withId(R.id.recyclerView)) .perform( RecyclerViewActions.actionOnItemAtPosition( ITEM_BELOW_THE_FOLD, click() ) ) // Match the text in an item below the fold and check that it's displayed. val itemElementText = "${activityRule.activity.resources .getString(R.string.item_element_text)} ${ITEM_BELOW_THE_FOLD.toString()}" onView(withText(itemElementText)).check(matches(isDisplayed())) }
Java
@Test public void scrollToItemBelowFold_checkItsText() { // First, scroll to the position that needs to be matched and click on it. onView(ViewMatchers.withId(R.id.recyclerView)) .perform(RecyclerViewActions.actionOnItemAtPosition(ITEM_BELOW_THE_FOLD, click())); // Match the text in an item below the fold and check that it's displayed. String itemElementText = activityRule.getActivity().getResources() .getString(R.string.item_element_text) + String.valueOf(ITEM_BELOW_THE_FOLD); onView(withText(itemElementText)).check(matches(isDisplayed())); }
Kotlin
@Test fun itemInMiddleOfList_hasSpecialText() { // First, scroll to the view holder using the isInTheMiddle() matcher. onView(ViewMatchers.withId(R.id.recyclerView)) .perform(RecyclerViewActions.scrollToHolder(isInTheMiddle())) // Check that the item has the special text. val middleElementText = activityRule.activity.resources .getString(R.string.middle) onView(withText(middleElementText)).check(matches(isDisplayed())) }
Java
@Test public void itemInMiddleOfList_hasSpecialText() { // First, scroll to the view holder using the isInTheMiddle() matcher. onView(ViewMatchers.withId(R.id.recyclerView)) .perform(RecyclerViewActions.scrollToHolder(isInTheMiddle())); // Check that the item has the special text. String middleElementText = activityRule.getActivity().getResources() .getString(R.string.middle); onView(withText(middleElementText)).check(matches(isDisplayed())); }
แหล่งข้อมูลเพิ่มเติม
หากต้องการข้อมูลเพิ่มเติมเกี่ยวกับการใช้รายการ Espresso ในการทดสอบ Android โปรดดู แหล่งข้อมูลต่อไปนี้
ตัวอย่าง
- DataAdapterSample:
แสดงจุดแรกเข้า
onData()
ของ Espresso สำหรับรายการและAdapterView
ออบเจ็กต์