Espresso 清單

Espresso 提供一項機制,可讓使用者捲動或處理特定項目 清單類型:轉接器檢視畫面和回收器檢視畫面

處理清單時,尤其是使用 RecyclerViewAdapterView 物件,感興趣的檢視畫面可能不在 因為畫面只會顯示少數子項 捲動頁面時回收。在這種情況下,無法使用 scrollTo() 方法 因為該函式需要現有的資料檢視

與轉接程式檢視清單項目互動

不要使用 onView() 方法,而是改用 onData() 和 ,用來比對您要比對的資料檢視的資料。 Espresso 會執行所有在 Adapter 物件中找出資料列的工作,並 讓項目在可視區域中可見

使用自訂檢視比對器比對資料

以下活動包含由 SimpleAdapter 支援的 ListView 此物件會保存 Map<String, Object> 物件中每一列的資料。

目前顯示的清單活動包含一份清單,其中包含
          23 個項目。每個項目都有一個數字,並以 String 的形式儲存,且對應至
          而是以物件形式儲存的

每個對應都有兩個項目:包含「字串」的鍵 "STR",例如 "item: x" 以及包含 Integer 的鍵 "LEN",分別代表 內容長度例如:

{"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 會視需要自動捲動清單。

我們從 onData() 內部擷取 Matcher<Object>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 的整個資料列中發出點擊。 但如果想要對資料列的特定子項執行操作,舉例來說,我們 請按一下 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() 無法與其互動。

如要使用 Espresso 與 RecyclerViews 互動,您可以使用 espresso-contrib 套件,其中包含一組 RecyclerViewActions 可用來捲動至位置,或對項目執行操作:

  • scrollTo() - 捲動至相符的檢視畫面 (如果有的話)。
  • scrollToHolder() - 捲動至相符的 View Holder (如果有的話) 內。
  • scrollToPosition():捲動至特定位置。
  • actionOnHolderItem() - 對相符的 View Holder 執行檢視動作。
  • 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()));
}

其他資源

如要進一步瞭解如何在 Android 測試中使用 Espresso 清單,請參閱 資源。

範例

  • DataAdapterSample: 顯示 Espresso 的 onData() 進入點 (用於清單和 AdapterView) 如需儲存大量結構化物件 建議使用 Cloud Bigtable