รายการเอสเพรสโซ

Espresso มีกลไกสำหรับเลื่อนหรือดำเนินการกับรายการใดรายการหนึ่ง ซึ่งได้แก่ มุมมองอะแดปเตอร์และมุมมองนักรีไซเคิล

เมื่อจัดการกับรายการ โดยเฉพาะรายการที่สร้างด้วย RecyclerView หรือ AdapterView มุมมองที่คุณสนใจอาจไม่ได้เปิด บนหน้าจอเพราะมีเด็กเพียงไม่กี่คนเท่านั้นที่แสดงและ เป็นการรีไซเคิลขณะที่คุณเลื่อน ใช้เมธอด scrollTo() ไม่ได้ในกรณีนี้ เนื่องจากจำเป็นต้องมีข้อมูลพร็อพเพอร์ตี้อยู่แล้ว

โต้ตอบกับรายการมุมมองรายการของอะแดปเตอร์

แทนที่จะใช้เมธอด onView() ให้เริ่มการค้นหาด้วย onData() และ ระบุตัวจับคู่กับข้อมูลที่สนับสนุนข้อมูลพร็อพเพอร์ตี้ที่คุณต้องการจับคู่ เอสเพรสโซจะทำงานทั้งหมดเพื่อค้นหาแถวในออบเจ็กต์ Adapter และ ซึ่งทำให้รายการปรากฏในวิวพอร์ต

จับคู่ข้อมูลโดยใช้ตัวจับคู่มุมมองที่กำหนดเอง

กิจกรรมด้านล่างมี ListView ซึ่งได้รับการสนับสนุนโดย SimpleAdapter ที่เก็บข้อมูลสำหรับแต่ละแถวในออบเจ็กต์ Map<String, Object>

กิจกรรมรายการที่แสดงบนหน้าจอในปัจจุบันประกอบด้วยรายการที่มี
          23 รายการ แต่ละรายการจะมีตัวเลขที่จัดเก็บเป็นสตริง ซึ่งจับคู่กับ
          หมายเลขอื่น ซึ่งจัดเก็บเป็นออบเจ็กต์แทน

แต่ละแผนที่มี 2 รายการ ได้แก่ คีย์ "STR" ที่มีสตริง เช่น "item: x" และคีย์ "LEN" ที่มี Integer ซึ่งแสดงถึง ความยาวของเนื้อหา เช่น

{"STR" : "item: 0", "LEN": 7}

โค้ดสําหรับการคลิกแถวที่มี "item: 50" ซึ่งมีลักษณะดังนี้

KotlinJava
onData(allOf(`is`(instanceOf(Map::class.java)), hasEntry(equalTo("STR"),
       
`is`("item: 50")))).perform(click())
onData(allOf(is(instanceOf(Map.class)), hasEntry(equalTo("STR"), is("item: 50"))))
   
.perform(click());

โปรดทราบว่า Espresso เลื่อนดูรายการโดยอัตโนมัติตามที่ต้องการ

มาแยก Matcher<Object> ภายใน onData() กัน is(instanceOf(Map.class)) จะจำกัดการค้นหาให้แสดงเฉพาะรายการ AdapterView ซึ่งได้รับการสนับสนุนโดยออบเจ็กต์ Map

ในกรณีของเรา ข้อความค้นหาด้านนี้ตรงกับแถวของมุมมองรายการทุกแถว แต่เรา คลิกรายการหนึ่งๆ โดยเฉพาะ เราจึงจำกัดการค้นหาให้แคบลงด้วยข้อมูลต่อไปนี้

KotlinJava
hasEntry(equalTo("STR"), `is`("item: 50"))
hasEntry(equalTo("STR"), is("item: 50"))

Matcher<String, Object> นี้จะตรงกับแผนที่ใดๆ ที่มีรายการที่มี คีย์ "STR" และค่า "item: 50" เพราะโค้ดที่ใช้ค้นหา และเราต้องการนำมาใช้ใหม่ในสถานที่อื่นๆ ลองเขียนบรรทัดที่กำหนดเอง ตัวจับคู่ withItemContent สำหรับกรณีนี้:

KotlinJava
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)
   
}
}
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:

KotlinJava
fun withItemContent(expectedText: String): Matcher<Object> {
    checkNotNull
(expectedText)
   
return withItemContent(equalTo(expectedText))
}
public static Matcher<Object> withItemContent(String expectedText) {
    checkNotNull
(expectedText);
   
return withItemContent(equalTo(expectedText));
}

ตอนนี้โค้ดสำหรับคลิกรายการนั้นสามารถทำได้ง่าย:

KotlinJava
onData(withItemContent("item: 50")).perform(click())
onData(withItemContent("item: 50")).perform(click());

สำหรับโค้ดทั้งหมดของการทดสอบนี้ โปรดดูที่เมธอด testClickOnItem50() ภายใน AdapterViewTest ชั้นเรียนและ LongListMatchers ที่กำหนดเองนี้ ตัวจับคู่ใน GitHub

ตรงกับมุมมองย่อยที่เจาะจง

ตัวอย่างด้านบนจะส่งออกการคลิกตรงกลางแถวทั้งแถวของ ListView แต่หากต้องการดำเนินการกับระดับย่อยที่เจาะจง ตัวอย่างเช่น เรา ต้องการคลิกคอลัมน์ที่ 2 ของแถว LongListActivity ซึ่งจะแสดง String.length ของเนื้อหาในคอลัมน์แรก:

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

เพียงเพิ่มข้อกำหนด onChildView() ลงในการใช้งาน DataInteraction:

KotlinJava
onData(withItemContent("item: 60"))
   
.onChildView(withId(R.id.item_size))
   
.perform(click())
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 ตัวอย่าง:

KotlinJava
@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"))
           
)
       
)
}
@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"))
           
));
}
KotlinJava
@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()))
}
@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()));
}
KotlinJava
@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()))
}
@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 ออบเจ็กต์