如何在Espresso的RecyclerView中声明?

我正在使用espresso-contrib在RecyclerView上执行操作,它的工作方式应该如此,例如:

 onView(withId(R.id.recycler_view)) .perform(RecyclerViewActions.actionOnItemAtPosition(0, click())); //click on first item 

我需要对它进行断言。 像这样的东西:

 onView(withId(R.id.recycler_view)) .perform(RecyclerViewActions.actionOnItemAtPosition(0, check(matches(withText("Test Text")))); 

但是,因为RecyclerViewActions当然是期待一个动作,它说错误的第二个参数types。 在espresso-contrib上没有RecyclerViewAssertions

有什么方法可以在回收者视图上执行断言?

Solutions Collecting From Web of "如何在Espresso的RecyclerView中声明?"

你应该看看Danny Roa的解决schemeCustom RecyclerView Actions并使用它像这样:

 onView(withRecyclerView(R.id.recycler_view) .atPositionOnView(1, R.id.ofElementYouWantToCheck)) .check(matches(withText("Test text"))); 

挺容易。 不需要额外的库。 做:

  onView(withId(R.id.recycler_view)) .check(matches(atPosition(0, withText("Test Text")))); 

如果你的ViewHolder使用ViewGroup,用withText()来包装withText() ,如:

 onView(withId(R.id.recycler_view)) .check(matches(atPosition(0, hasDescendant(withText("Test Text"))))); 

用你可能会放入你的Utils类的方法。

 public static Matcher<View> atPosition(final int position, @NonNull final Matcher<View> itemMatcher) { checkNotNull(itemMatcher); return new BoundedMatcher<View, RecyclerView>(RecyclerView.class) { @Override public void describeTo(Description description) { description.appendText("has item at position " + position + ": "); itemMatcher.describeTo(description); } @Override protected boolean matchesSafely(final RecyclerView view) { RecyclerView.ViewHolder viewHolder = view.findViewHolderForAdapterPosition(position); if (viewHolder == null) { // has no item on such position return false; } return itemMatcher.matches(viewHolder.itemView); } }; } 

如果您的项目最初可能在屏幕上不可见,请在之前滚动到该项目:

  onView(withId(R.id.recycler_view)) .perform(scrollToPosition(87)) .check(matches(atPosition(87, withText("Test Text")))); 

只是为了增强riwnodennyk的答案,如果你的ViewHolder是一个ViewGroup而不是像TextView这样的直接View对象,那么你可以添加hasDescendant匹配器来匹配ViewGroup中的TextView对象。 例:

 onView(withId(R.id.recycler_view)) .check(matches(atPosition(0, hasDescendant(withText("First Element"))))); 

我一直在同一个问题上挣扎,在这个问题上我有一个6个物品的回收站视图,然后我必须select位置5,第五个视图不可见。
上述解决scheme也可以。 另外,我知道它有点晚,但认为它值得分享。

我做了一个简单的解决scheme,如下所示:

 onView(withId(R.id.recylcer_view)) .perform(RecyclerViewActions.actionOnItem( hasDescendant(withText("Text of item you want to scroll to")), click())); 

RecyclerViewActions.actionOnItem – 在viewHolderMatcher匹配的视图上执行ViewAction

  1. RecyclerView滚动到RecyclerView所匹配的视图
  2. 在匹配的视图上执行操作

更多细节可以在RecyclerViewActions.actionOnItemfind

就我而言,有必要合并Danny Roa和riwnodennyk的解决scheme:

 onView(withId(R.id.recyclerview)) .perform(RecyclerViewActions.scrollToPosition(80)) .check(matches(atPositionOnView(80, withText("Test Test"), R.id.targetview))); 

和方法:

 public static Matcher<View> atPositionOnView(final int position, final Matcher<View> itemMatcher, @NonNull final int targetViewId) { return new BoundedMatcher<View, RecyclerView>(RecyclerView.class) { @Override public void describeTo(Description description) { description.appendText("has view id " + itemMatcher + " at position " + position); } @Override public boolean matchesSafely(final RecyclerView recyclerView) { RecyclerView.ViewHolder viewHolder = recyclerView.findViewHolderForAdapterPosition(position); View targetView = viewHolder.itemView.findViewById(targetViewId); return itemMatcher.matches(targetView); } }; } 

Danny Roa的解决scheme非常棒,但对于我刚刚滚动的屏幕外物品却无效。 修复正在取代这个:

 View targetView = recyclerView.getChildAt(this.position) .findViewById(this.viewId); 

有了这个:

 View targetView = recyclerView.findViewHolderForAdapterPosition(this.position) .itemView.findViewById(this.viewId); 

TestUtils类中 。