Espresso测试ListView项目单击childView的操作(扩展了FrameLayout)

时间:2018-08-31 05:54:48

标签: java android android-espresso android-testing

我有一个活动,在这个活动中,我有多个子视图:

public class CategoriesActivity extends AppCompatActivity {

    private StaggeredGridLayoutManager categoryGridLayoutManager;
    private DrawerLayout mDrawerLayout;
    private RecyclerView recyclerView;
    private NavigationView navigationView;
    private List<Category> categoryList;
    private Toolbar toolbar;
    private MaterialSearchView searchView;
    ...
 }

我有一个工具栏,在这个工具栏上有一个菜单按钮和一个搜索按钮。

主屏幕如下:

[初始屏幕](https://imgur.com/bk0GXyOm.png

单击搜索按钮时,搜索视图将在现有列表视图的顶部打开,并且看起来像这样:

[搜索屏幕](https://imgur.com/XefVGFwm.png

我有兴趣测试搜索的功能,更确切地说,是使用Espresso测试单击搜索视图的每一行的操作(例如,选中“ Hello”,然后单击“ Bonjour”)等)。

到目前为止,我所拥有的是以下内容(获得建议的数量有用):

@RunWith(AndroidJUnit4.class)
public class CategoryActivityInstrumentedTests {
    @Rule
    public ActivityTestRule<CategoriesActivity> activityActivityTestRule = new ActivityTestRule<CategoriesActivity>(CategoriesActivity.class);

    @Before
    public void init(){
        //activityActivityTestRule.getActivity().getSupportFragmentManager().beginTransaction();
        Utils.level = 2;
    }

    @Test
    public void TestSuggestions(){
        onView(withId(R.id.action_search)).perform(click());
        onView(withId(R.id.search_view)).perform(new MyCustomViewAction());
    }

    public class MyCustomViewAction implements ViewAction {
        int size = 0;
        @Override
        public Matcher<View> getConstraints(){
            return isAssignableFrom(MaterialSearchView.class);
        }


        @Override
        public String getDescription(){
            return "whatever, size = " + size;
        }

        @Override
        public void perform(UiController uiController, View view){
            MaterialSearchView yourCustomView = (MaterialSearchView) view;
            size = yourCustomView.getSuggestionsCount();
            System.out.println(size);
            yourCustomView.mSuggestionsListView.performItemClick(yourCustomView.mSuggestionsListView.getAdapter().getView(1, null, null), 1, yourCustomView.mSuggestionsListView.getAdapter().getItemId(1));
                    //getItemAtPosition(0) toString(); // .performClick();
            Log.e(Constants.TAG_CategoriesActivity, " size = " + size);

        }

    }
}

问题是我无法在此活动中获得此列表(搜索视图包含建议列表),因此,我无法对该视图的元素执行单击操作。

当我在MyCustomViewAction内部执行单击时,它可以工作,但由于未初始化viewGroup,所以在主活动中出现了空指针异常。

这是我的搜索视图的代码:

public class MaterialSearchView extends FrameLayout implements Filter.FilterListener {

    //Views
    private View mSearchLayout;
    private View mTintView;
    public ListView mSuggestionsListView;
    private EditText mSearchSrcTextView;
    private ImageButton mBackBtn;
    private ImageButton mVoiceBtn;
    private ImageButton mEmptyBtn;
    private RelativeLayout mSearchTopBar;
    ...
}

有什么想法吗? 谢谢!


编辑

我在测试方法TestSuggestions()中尝试了以下调用:

onData(allOf(withText("Bonjour"))) // Find the row in the list .inAdapterView(withId(R.id.search_view)) // Find the list in the view hierarchy .perform(click());

我遇到以下异常:

`I/TestRunner: android.support.test.espresso.PerformException: Error performing 'load adapter data' on view 'with id: com...:id/search_view'.`

1 个答案:

答案 0 :(得分:0)

我终于找到了解决方案(至少有2个解决方案):

第一个解决方案:

    @Test
    public void TestSuggestions1(){
        for (int i=0 ; i<4081; i++) {

            onView(withId(R.id.action_search)).perform(click());    // opens the search
            Espresso.pressBack();   // performs the go back action to dismiss the keyboard
            onData(anything())      // selects the actual item at the desired position (which opens another activity)
                    .atPosition(i)
                    .perform(click());
            Espresso.pressBack();   // performs the go back action from the newer activity
            Log.e("TestSuggestions", " i = " + i);
        }
    }

我走到4081年,因为那是我的建议数量。

第二个解决方案:

    @Test
    public void TestSuggestions2() {
        for (i = 0; i < 4081; i++) {
            onView(withId(R.id.action_search)).perform(click());    // opens the search
            try {
                Thread.sleep(250);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Espresso.pressBack();   // performs the go back action from the newer activity
            onView(withId(R.id.search_view)).perform(new MyCustomViewAction()); // selects the actual item at the desired position (which opens another activity)
            try {
                Thread.sleep(250);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Espresso.pressBack();
        }
    }

具有以下MyCustomViewAction:

    public class MyCustomViewAction implements ViewAction {
        int size = 0;

        @Override
        public Matcher<View> getConstraints(){
            return isAssignableFrom(MaterialSearchView.class);
        }

        @Override
        public String getDescription(){
            return "whatever, size = " + size;
        }

        @Override
        public void perform(UiController uiController, View view){
            MaterialSearchView yourCustomView = (MaterialSearchView) view;
            size = yourCustomView.getSuggestionsCount();
            yourCustomView.mSuggestionsListView.performItemClick(yourCustomView.mSuggestionsListView.getAdapter().getView(i, null, null), i, yourCustomView.mSuggestionsListView.getAdapter().getItemId(i));
            Log.e(Constants.TAG_CategoriesActivity, " size = " + size);
        }
    }

其中i是我的TestClass中的全局变量,从0开始。