Espresso 提供一項機制,可讓使用者捲動或處理特定項目 清單類型:轉接器檢視畫面和回收器檢視畫面
處理清單時,尤其是使用 RecyclerView
或
AdapterView
物件,感興趣的檢視畫面可能不在
因為畫面只會顯示少數子項
捲動頁面時回收。在這種情況下,無法使用 scrollTo()
方法
因為該函式需要現有的資料檢視
與轉接程式檢視清單項目互動
不要使用 onView()
方法,而是改用 onData()
和
,用來比對您要比對的資料檢視的資料。
Espresso 會執行所有在 Adapter
物件中找出資料列的工作,並
讓項目在可視區域中可見
使用自訂檢視比對器比對資料
以下活動包含由 SimpleAdapter
支援的 ListView
此物件會保存 Map<String, Object>
物件中每一列的資料。
每個對應都有兩個項目:包含「字串」的鍵 "STR"
,例如
"item: x"
以及包含 Integer
的鍵 "LEN"
,分別代表
內容長度例如:
{"STR" : "item: 0", "LEN": 7}
含有「item: 50」資料列的點擊代碼如下所示:
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
物件支援。
在本範例中,此查詢的一方面符合清單檢視的每一列, 想特別點選某個項目,因此我們想使用:
這個 Matcher<String, Object>
會比對任何包含
"STR"
鍵和 "item: 50"
值。因為查詢這個程式碼的程式碼
想要在其他地區重複使用
我們要撰寫一個自訂的
為此,withItemContent
比對器:
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
物件:
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));
}
現在,點選項目的程式碼很簡單:
onData(withItemContent("item: 50")).perform(click())
onData(withItemContent("item: 50")).perform(click());
如需這項測試的完整程式碼,請參閱 testClickOnItem50()
方法。
在
AdapterViewTest
類別和
這項自訂 LongListMatchers
GitHub 的比對器。
與特定子項檢視畫面相符
上述範例會在 ListView
的整個資料列中發出點擊。
但如果想要對資料列的特定子項執行操作,舉例來說,我們
請按一下 LongListActivity
這列的第二欄
這會在第一欄中顯示內容的 String.length:
只要在onChildView()
DataInteraction
:
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 範例:
@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"))
));
}
@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()));
}
@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