如何让 Espresso 单击特定的 RecyclerView 项目?

Posted

技术标签:

【中文标题】如何让 Espresso 单击特定的 RecyclerView 项目?【英文标题】:How to let Espresso click a specific RecyclerView item? 【发布时间】:2016-11-01 18:12:03 【问题描述】:

我正在尝试使用 Espresso 为我使用 RecyclerViewandroid 应用程序编写仪器测试。这是主要布局:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_
    android:layout_>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/grid"
        android:layout_
        android:layout_
        app:layout_behavior="@string/appbar_scrolling_view_behavior"/>

</android.support.design.widget.CoordinatorLayout>

...和项目视图布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_>

    <TextView
        android:id="@+id/label"
        android:layout_
        android:layout_/>

</RelativeLayout>

这意味着屏幕上有几个TextViews,它们都有label id。我正在尝试单击特定标签。我试着让 Espresso 测试记录器生成代码:

onView(allOf(withId(R.id.grid), isDisplayed()))
    .perform(actionOnItemAtPosition(5, click()));

我宁愿做这样的事情:

// Not working
onView(allOf(withId(R.id.grid), isDisplayed()))
    .perform(actionOnItem(withText("Foobar"), click()));

读数

我阅读了很多关于该主题的内容,但仍然无法弄清楚如何根据其内容测试RecyclerView 项目不是基于其位置索引。

Advanced Android Espresso - Slide on RecyclerViewActions(陈秋琪) RecyclerView and espresso, a complicated story(Patrick Bacon,2015 年 7 月 18 日) Espresso – Testing RecyclerViews at Specific Positions(Romain Piel,2016 年 4 月 15 日)

【问题讨论】:

【参考方案1】:

您可以实现您的自定义 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 一起使用。通过这种方式,我们避免了自定义匹配器的多次匹配,并且只针对实际显示我们主题的项目。

【讨论】:

有谁知道appendText的作用是什么? 通过这种方式,您可以自定义错误描述以防失败。【参考方案2】:

actionOnItem() 匹配 ViewHolder 的 itemView。在这种情况下,TextView 被包裹在 RelativeLayout 中,因此您需要更新 Matcher 来解决它。

onView(allOf(withId(R.id.grid), isDisplayed()))
    .perform(actionOnItem(withChild(withText("Foobar")), click()));

你也可以使用hasDescendant()来包裹你的匹配器是一个更复杂的嵌套情况。

【讨论】:

不管视图嵌套多深,hasDescendant() 是否会自动遍历层级?还是我必须使用hasDescendant(hasDescendant(...)) 是的,hasDescendant() 将从 onView() 部分中的根处理整个视图层次结构。在 recyclerview 操作的情况下,根是 itemView

以上是关于如何让 Espresso 单击特定的 RecyclerView 项目?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Espresso 测试中单击快餐栏按钮?

使用 Espresso 和 Spoon 运行特定测试

如何使用 Espresso 测试特定活动?

Espresso - 如何定位并单击ListView中的第一个项目

如何在 Android Espresso Kakao 测试中单击 webview 按钮

如何让浓缩咖啡测试在特定条件下失败