如何点击Espresso中RecyclerView内的项目

时间:2014-12-10 08:45:05

标签: android android-recyclerview android-espresso

我有一个RecyclerView(R.id.recyclerView),其中每一行都有一个图像(R.id.row_image)和一个TextView。我想点击第一行的图片 我尝试过使用onData(..),但它似乎无法正常工作。

10 个答案:

答案 0 :(得分:73)

使用RecyclerViewActions

onView(withId(R.id.recyclerView))
    .perform(actionOnItemAtPosition(0, click()));

将此内容包含在您的gradle脚本中:

dependencies {
    androidTestCompile 'com.android.support.test:testing-support-lib:0.1'
    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.0'
    androidTestCompile 'com.android.support.test.espresso:espresso-contrib:2.0'
}

答案 1 :(得分:21)

只是添加Gabor的答案(这是自Espresso 2.0以来的正确和完整答案)。

使用espresso-contribRecyclerView时,您可能会遇到问题(请参阅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答案的评论,因为我还没有权利发表评论)

答案 2 :(得分:15)

编辑:

Espresso 2.0已发布,the changelog包含以下内容:

  

新功能

     
      
  • 浓咖啡的contrib      
        
    • RecyclerViewActions:处理与RecyclerViews的交互
    •   
  •   

旧答案

我还没有自己测试过这个问题,但Thomas Keller posted this在G +上有一个简短的解释和一个带有必要视图匹配的Gist的链接。

  

由于新RecyclerView API继承自ViewGroup而非AdapterView,因此您无法使用Espresso的onData()来测试使用此组件的布局。

Link to Gist

我会附上代码,只是为了完整起见(注意:不是我的!所有功劳归功于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")));

答案 3 :(得分:5)

您应该使用自定义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));
    }
}

答案 4 :(得分:2)

您无需添加&#34; testing-support-lib&#34;,也不会添加&#34; espresso:espresso-core&#34;。当&#34; espresso:espresso-contrib&#34;已添加。

<强> 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()));

答案 5 :(得分:2)

我找到了两种方法:

  1. 假设你有一个id为#34; R.id.description&#34;的文本视图。对于RecyclerView中的每个项目。您可以这样做以匹配特定的孩子:
  2. onView(allOf(withId(R.id.place_description),withText("what"))).perform(click());

    1. Android Testing Codelab的教程 https://codelabs.developers.google.com/codelabs/android-testing/#0
    2. `

      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());
      

答案 6 :(得分:2)

与上述相同的答案,但由于需要提供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

中的最新浓缩咖啡

答案 7 :(得分:1)

我关注了@ Gabor的回答但是当我收录了这些库时,我达到了dex限制!

所以,我删除了这些库,添加了这个getInstrumentation().waitForIdleSync();,然后只调用了onView(withId...))...

完美无缺。

在您的情况下,您将拥有多个具有相同ID的图像视图,因此您必须弄清楚如何选择特定列表项。

答案 8 :(得分:1)

当我发布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相同。这样我们就可以避免我们的自定义匹配器的多个匹配项和仅实现显示我们主题的目标项。

答案 9 :(得分:0)

使用此代码,您可以滚动回收器视图以找到带有文本的商品并对其执行点击或其他操作。

依赖项

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()));
}