[英]How to click on an item inside a RecyclerView in Espresso
我有一個 RecyclerView (R.id.recyclerView),其中每一行都有一個圖像 (R.id.row_image) 和一個 TextView。 我想單擊第一行中的圖像。
我試過使用 onData(..) 但它似乎不起作用。
onView(withId(R.id.recyclerView))
.perform(actionOnItemAtPosition(0, click()));
將此包含在您的 gradle 腳本中:
dependencies {
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.0'
androidTestCompile 'com.android.support.test.espresso:espresso-contrib:2.0'
}
只是為了添加 Gabor 的答案(這是自 Espresso 2.0 以來正確且完整的答案)。
您目前在使用espresso-contrib
和RecyclerView
時可能會遇到問題(請參閱android-test-kit 票證)。
解決方法是在上面提到的espresso-contrib
依賴項 Gabor 中添加此排除項:
androidTestCompile('com.android.support.test.espresso:espresso-contrib:2.0') {
exclude group: 'com.android.support', module: 'appcompat'
exclude group: 'com.android.support', module: 'support-v4'
exclude module: 'recyclerview-v7'
}
(這是一個答案而不是對 Gabor 答案的評論,因為我還沒有發表評論的權利)
Espresso 2.0 已經發布,更新日志包括以下內容:
新功能
- 濃縮咖啡貢獻
- RecyclerViewActions:處理與 RecyclerViews 的交互
我自己還沒有測試過這個,但是 Thomas Keller 在 G+ 上發布了這個,並附有一個簡短的解釋和一個指向帶有必要視圖匹配器的 Gist 的鏈接。
由於新的
RecyclerView
API 繼承自ViewGroup
而不是AdapterView
,因此您不能使用 Espresso 的onData()
來測試使用此組件的布局。
我會附上代碼,只是為了完整起見(注意:不是我的!所有功勞都歸功於 Thomas Keller)
視圖匹配器:
public class ViewMatchers {
@SuppressWarnings("unchecked")
public static Matcher<View> withRecyclerView(@IdRes int viewId) {
return allOf(isAssignableFrom(RecyclerView.class), withId(viewId));
}
@SuppressWarnings("unchecked")
public static ViewInteraction onRecyclerItemView(@IdRes int identifyingView, Matcher<View> identifyingMatcher, Matcher<View> childMatcher) {
Matcher<View> itemView = allOf(withParent(withRecyclerView(R.id.start_grid)),
withChild(allOf(withId(identifyingView), identifyingMatcher)));
return Espresso.onView(allOf(isDescendantOfA(itemView), childMatcher));
}
}
和示例用法:
onRecyclerItemView(R.id.item_title, withText("Test"), withId(R.id.item_content))
.matches(check(withText("Test Content")));
您應該使用自定義 ViewAction:
public void clickOnImageViewAtRow(int position) {
onView(withId(R.id.recycler_view)).perform(RecyclerViewActions.actionOnItemAtPosition(position, new ClickOnImageView()));
}
public class ClickOnImageView implements ViewAction{
ViewAction click = click();
@Override
public Matcher<View> getConstraints() {
return click.getConstraints();
}
@Override
public String getDescription() {
return " click on custom image view";
}
@Override
public void perform(UiController uiController, View view) {
click.perform(uiController, view.findViewById(R.id.imageView));
}
}
我找到了兩種方法:
onView(allOf(withId(R.id.place_description),withText("what"))).perform(click());
`
public Matcher<View> withItemText(final String itemText) {
checkArgument(!TextUtils.isEmpty(itemText),"cannot be null");
return new TypeSafeMatcher<View>() {
@Override
protected boolean matchesSafely(View item) {
return allOf(isDescendantOfA(isAssignableFrom(RecyclerView.class)),withText(itemText)).matches(item);
}
@Override
public void describeTo(Description description) {
description.appendText("is descendant of a RecyclerView with text" + itemText);
}
};
}
`
然后,這樣做:
onView(withItemText("what")).perform(click());
與上面相同的答案,但是由於您必須提供 Viewholder 類型,因此進行了一些小的修改
使用 RecyclerViewActions
fun tapOnRecyclerView(@IdRes resId: Int , position: Int) = onView(withId(resId))
.perform(actionOnItemAtPosition<RecyclerView.ViewHolder>(position, click()));
並將此庫包含在您的項目中,請使用此
androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion"
androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion"
更喜歡使用此鏈接中的最新濃縮咖啡版本
您不需要添加“testing-support-lib”,也不需要添加“espresso:espresso-core”。 當添加“espresso:espresso-contrib”時,它們是可傳遞的。
建造等級
dependencies {
androidTestCompile 'com.android.support.test:runner:0.3'
androidTestCompile 'com.android.support.test:rules:0.3'
androidTestCompile 'com.android.support.test.espresso:espresso-contrib:2.2'
}
用法:
onView(withId(R.id.recyclerView)).perform(
RecyclerViewActions.actionOnItemAtPosition(0, click()));
我遵循了@Gabor 的回答,但是當我包含這些庫時,我達到了 dex 限制!
所以,我刪除了庫,添加了這個getInstrumentation().waitForIdleSync();
然后只是調用onView(withId...))...
完美運行。
在您的情況下,您將擁有多個具有相同 ID 的圖像視圖,因此您必須弄清楚如何選擇特定列表項。
正如我在這里發布的那樣,您可以實現您的自定義RecyclerView
匹配器。 假設您有RecyclerView
,其中每個元素都有您要匹配的主題:
public static Matcher<RecyclerView.ViewHolder> withItemSubject(final String subject) {
Checks.checkNotNull(subject);
return new BoundedMatcher<RecyclerView.ViewHolder, MyCustomViewHolder>(
MyCustomViewHolder.class) {
@Override
protected boolean matchesSafely(MyCustomViewHolder viewHolder) {
TextView subjectTextView = (TextView)viewHolder.itemView.findViewById(R.id.subject_text_view_id);
return ((subject.equals(subjectTextView.getText().toString())
&& (subjectTextView.getVisibility() == View.VISIBLE)));
}
@Override
public void describeTo(Description description) {
description.appendText("item with subject: " + subject);
}
};
}
和用法:
onView(withId(R.id.my_recycler_view_id)
.perform(RecyclerViewActions.actionOnHolderItem(withItemSubject("My subject"), click()));
基本上你可以匹配任何你想要的。 在這個例子中,我們使用了主題TextView
但它可以是RecyclerView
項目中的任何元素。
需要澄清的另一件事是檢查可見性(subjectTextView.getVisibility() == View.VISIBLE)
。 我們需要它,因為有時RecyclerView
其他視圖可以具有相同的主題,但它會與View.GONE
。 通過這種方式,我們避免了自定義匹配器的多次匹配,並且只針對實際顯示我們主題的項目。
使用此代碼,您可以滾動回收站視圖以找到您的項目 withText 並對其執行單擊或其他操作。
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.3.0'
@Test
public void scrollRecyclerViewAndClick() {
onView(withId(R.id.recycler_view)).
perform(RecyclerViewActions.
actionOnItem(withText("specific string"), click()));
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.