【发布时间】:2014-12-10 08:45:05
【问题描述】:
我有一个 RecyclerView (R.id.recyclerView),其中每一行都有一个图像 (R.id.row_image) 和一个 TextView。我想点击第一行的图片。
我尝试使用 onData(..) 但它似乎不起作用。
【问题讨论】:
标签: android android-recyclerview android-espresso
我有一个 RecyclerView (R.id.recyclerView),其中每一行都有一个图像 (R.id.row_image) 和一个 TextView。我想点击第一行的图片。
我尝试使用 onData(..) 但它似乎不起作用。
【问题讨论】:
标签: android android-recyclerview android-espresso
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'
}
【讨论】:
check(isDisplayed()) ?
只是添加到 Gabor 的答案(这是自 Espresso 2.0 以来正确且完整的答案)。
您在使用espresso-contrib 和RecyclerViews 时可能会遇到问题(请参阅android-test-kit ticket)。
一种解决方法是在上面提到的 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 答案的评论,因为我还无权发布 cmets)
【讨论】:
Espresso 2.0 已经发布,the changelog 包括以下内容:
新功能
- 浓缩咖啡贡献
- RecyclerViewActions:处理与 RecyclerViews 的交互
我自己还没有对此进行测试,但是 G+ 上的 Thomas Keller posted this 提供了简短的解释和指向带有必要视图匹配器的 Gist 的链接。
由于新的
RecyclerViewAPI 继承自ViewGroup而不是AdapterView,因此您不能使用 Espresso 的onData()来测试使用此组件的布局。
为了完整起见,我将附上代码(注意:不是我的!所有功劳归于 Thomas Keller)
ViewMatcher:
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));
}
}
【讨论】:
与上面相同的答案,但是由于您必须提供 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"
更喜欢使用来自link 的最新 espresso 版本
【讨论】:
我找到了两种方法:
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());
【讨论】:
您不需要添加“testing-support-lib”,也不需要添加“espresso:espresso-core”。当添加“espresso:espresso-contrib”时,它们是可传递的。
build.grade
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 的图像视图,因此您必须弄清楚如何选择特定列表项。
【讨论】:
正如我发布的here,您可以实现您的自定义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 一起使用。通过这种方式,我们避免了自定义匹配器的多次匹配,并且只针对实际显示我们主题的项目。
【讨论】:
使用此代码,您可以滚动回收站视图以查找带有文本的项目并对其执行单击或其他操作。
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()));
}
【讨论】: