将Espresso与嵌入式工具栏一起使用

时间:2017-03-29 22:05:29

标签: java android testing android-espresso

我有一个在RecyclerView中使用的具有垂直LinearLayout Manager的列表项。我正在使用espresso,我想模拟单击id / action_save菜单项。以下是我最近尝试解决这个问题的尝试。我尝试过将onData方法与onChildView结合使用,但是MenuItem不是View。如果菜单项位于操作栏中的工具栏中,但嵌入在RecyclerView中,则onView和withId方法可以正常工作。

我尝试使用android studio中的espresso录制功能进行录制,但是,它会注入类似于Espresso click menu item的代码。再次运行测试用例会导致测试引发异常。

列出项目

<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cardCornerRadius="0dp"
    app:cardUseCompatPadding="true">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <android.support.v7.widget.Toolbar 
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimaryDark"
            android:elevation="4dp"
            android:minHeight="?attr/actionBarSize"
            app:popupTheme="@style/MyDarkToolbarStyle"
            app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />


        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1">

            <ProgressBar
                android:id="@+id/progress"
                style="@style/Widget.AppCompat.ProgressBar"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:indeterminate="true" />

            <android.support.v7.widget.AppCompatImageView
                android:id="@+id/imgPalette"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:minHeight="250dp" />
        </RelativeLayout>

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:layout_marginTop="-2dp"
            android:elevation="4dp"
            android:outlineProvider="bounds"
            android:paddingTop="2dp">
            <FrameLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@color/colorPrimaryDark">

                <android.support.v7.widget.RecyclerView
                    android:id="@+id/recyclerView"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent" />
            </FrameLayout>
        </FrameLayout>
    </LinearLayout>
</android.support.v7.widget.CardView>

菜单

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
       android:id="@+id/action_save"
       android:title="@string/save"
       app:showAsAction="never" />
</menu>

主要布局

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    ...
    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/banner" />
    ...
    </RelativeLayout>

Java(Espresso / JUnit测试用例)

...
// mProducts is a list that is backed by the adapter and is of Type Product
for (int i = 0; i < mProducts.size(); i++) {
        onView(allOf(withId(R.id.recyclerView), withParent(withId(R.id.container))))
                .perform(actionOnItemAtPosition(i, clickOverflow(R.id.toolbar)));

        // Add delay for system to respond to overflow being opened
        SystemClock.sleep(1000);
        onView(withId(R.id.recyclerView)).perform(actionOnItemAtPosition(i, clickMenuItem(R.id.toolbar, R.id.action_save)));
    }
...
public static ViewAction clickMenuItem(final int toolbarId, final int id) {
    return new ViewAction() {
        @Override
        public Matcher<View> getConstraints() {
            return null;
        }

        @Override
        public String getDescription() {
            return "Click on a child view with specified id.";
        }

        @Override
        public void perform(UiController uiController, View view) {
            Toolbar toolbar = (Toolbar) view.findViewById(toolbarId);
            for (int i = 0; i < toolbar.getChildCount(); i++) {
                if (toolbar.getChildAt(i) instanceof ActionMenuView) {
                    ViewGroup viewGroup = ((ViewGroup) toolbar.getChildAt(i));
                    for (int j = 0; j < viewGroup.getChildCount(); j++) {
                        if (viewGroup.getChildAt(j).getId() == id) {
                            viewGroup.getChildAt(j).performClick();
                            break;
                        }
                    }
                }
            }
        }
    };
}


public static ViewAction clickOverflow(final int toolbarId) {
    return new ViewAction() {
        @Override
        public Matcher<View> getConstraints() {
            return null;
        }

        @Override
        public String getDescription() {
            return "Click on a child view with specified id.";
        }

        @Override
        public void perform(UiController uiController, View view) {
            Toolbar toolbar = (Toolbar) view.findViewById(toolbarId);
            ((ViewGroup) toolbar.getChildAt(0)).getChildAt(0).performClick();
        }
    };
}

错误

android.support.test.espresso.NoMatchingViewException: No views in hierarchy found matching: with id: com.variable.inspire:id/recyclerView
If the target view is not part of the view hierarchy, you may need to use Espresso.onData to load it from one of the following AdapterViews:android.support.v7.widget.MenuPopupWindow$MenuDropDownListView{92d26ac VFED.VC.. .F...... 0,0-515,252}

更新#1

这不能解决我的问题,但通过直接显示菜单项而不是溢出菜单中提供了一种解决方法。我的问题仍然是使用浓缩咖啡,你可以打开溢出菜单并单击其中的项目。

onView(allOf(withId(R.id.recyclerView), withParent(withId(R.id.container)))).perform(actionOnItemAtPosition(i, clickMenuItem(R.id.toolbar, R.id.action_save)));

0 个答案:

没有答案