繁体   English   中英

如何在 Espresso 中单击 RecyclerView 中的项目

[英]How to click on an item inside a RecyclerView in Espresso

我有一个 RecyclerView (R.id.recyclerView),其中每一行都有一个图像 (R.id.row_image) 和一个 TextView。 我想单击第一行中的图像。
我试过使用 onData(..) 但它似乎不起作用。

使用RecyclerViewActions

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-contribRecyclerView时可能会遇到问题(请参阅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));
    }
}

我找到了两种方法:

  1. 假设您在 RecyclerView 中的每个项目都有一个 ID 为“R.id.description”的文本视图。 您可以这样做以匹配特定的孩子:

onView(allOf(withId(R.id.place_description),withText("what"))).perform(click());

  1. 来自 Android 测试 Codelab 的教程https://codelabs.developers.google.com/codelabs/android-testing/#0

`

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM