简体   繁体   English

Android Expresso验证上下文菜单和actionBar项

[英]Android Expresso verifying Context Menu and actionBar items

I have a list where every row contains a name and a button that invokes a Context Menu of options. 我有一个列表,其中每一行都包含一个名称和一个调用选项的上下文菜单的按钮。 I would like to write a test that verifies the following things 我想编写一个验证以下内容的测试

  1. the context menu contains the correct NUMBER of items 上下文菜单包含正确数量的项目
  2. the context menu contains the correct VALUES 上下文菜单包含正确的值
  3. the context menu does not contain any unwarranted options (the checks 1and 2 above will test this case) 上下文菜单不包含任何不必要的选项(上面的检查1和2将测试这种情况)

I would also like to test the contents of the actionBar and actionBar overflow menu when the item is long selected. 当长时间选择该项时,我还想测试actionBar和actionBar溢出菜单的内容。

For both tests, I can write a check that ensures there is a view element with the correct "label" displayed (ie finding the view using onView(withText(this.elementText)). However I have 2 actions which have the same label but different IDs and I need to ensure the correct action is in the context menu/long click menu. 对于这两个测试,我都可以编写检查以确保显示的视图元素具有正确的“标签”(即使用onView(withText(this.elementText)查找视图))。但是,我有2个动作具有相同的标签,但不同的ID,我需要确保上下文菜单/长按菜单中的操作正确。

I can not use the ID I specified in the XML for my context menu's menu because Android's Context Menu views do not have those IDs, instead they contain an internal Android ID (see the screenshot below). 我无法在上下文菜单的菜单中使用在XML中指定的ID,因为Android的上下文菜单视图没有这些ID,而是包含一个内部Android ID(请参见下面的屏幕截图)。 在此处输入图片说明

When I wrote tests using Robotium, i had to get all current views of a certain type and the parse through them checking if they are the actionBar items, see sample code below. 当我使用Robotium编写测试时,我必须获取某种类型的所有当前视图,并通过它们进行解析以检查它们是否为actionBar项,请参见下面的示例代码。

public static List<MenuItemImpl> getLongClickMenuItems(String itemName) {
    List<MenuItemImpl> menuItems = new ArrayList<>();

    // long select the item
    solo.clickLongOnText(itemName);

    // get the children of the of the long click action bar
    ArrayList<ActionMenuView> outViews = solo.getCurrentViews(ActionMenuView.class, solo.getView(R.id.action_mode_bar));

    if (!outViews.isEmpty()) {
        // get the first child which contains the action bar actions
        ActionMenuView actionMenuView = outViews.get(0);
        // loop over the children of the ActionMenuView which is the individual ActionMenuItemViews
        // only a few fit will fit on the actionBar, others will be in the overflow menu
        int count = actionMenuView.getChildCount();
        for (int i = 0; i < count; i++) {
            View child = actionMenuView.getChildAt(i);

            if (child instanceof ActionMenuItemView) {
                menuItems.add(((ActionMenuItemView) child).getItemData());
            } else {
                // this is the more button, click on it and wait for the popup window
                // which will contain a list of ListMenuItemView
                // As we are using the AppCompat the actionBar's menu items are the
                // the AppCompat's ListMenuItemView (android.support.v7.view.menu.ListMenuItemView)
                // In the context menu, the menu items are Android's native ListMenuItemView
                // (com.android.internal.view.menu.ListMenuItemView)
                solo.clickOnView(child);
                solo.waitForView(ListMenuItemView.class);
                ArrayList<ListMenuItemView> popupItems = solo.getCurrentViews(ListMenuItemView.class);
                for (ListMenuItemView lvItem : popupItems) {
                    menuItems.add(lvItem.getItemData());
                }

                // close the more button actions menu
                solo.goBack();
            }
        }
    }

    // get out of long click mode
    solo.goBack();

    return menuItems;
}

Does anyone know how I can get the list of Context Row menu items using Expresso. 有谁知道我如何使用Expresso获得“上下文行”菜单项的列表。

Does anyone know how I can get the actionBar items (including all items in the overflow menu) using Expresso? 有谁知道我如何使用Expresso获得actionBar项目(包括溢出菜单中的所有项目)?

If I understand your question correctly, you should be able to use on the onData() method to interact with the context menus as they are just AdapterViews (notice from your screenshot the popup is a ListPopupWindow$DropDownListView ). 如果我正确理解了您的问题,那么您应该可以在onData()方法上与上下文菜单进行交互,因为它们只是AdapterViews (注意,屏幕快照中的弹出窗口是ListPopupWindow$DropDownListView )。

So you should be able to do something like this: 因此,您应该能够执行以下操作:

onView(withText("Item Label")).perform(longClick());
final int expectedItemCount = 10;

// Now the floating popup should be showing,
// first assert it has the expected item count

onView(isAssignableFrom(AdapterView.class))
.check(matches(withItemCount(expectedItemCount)));

// Now assert each entry (which should just be a string) is shown correctly
for (int i = 0; i < expectedItemCount; i++) {
    String expectedItemText = getExpectedItemTextForIndex(i);
    onData(instanceOf(String.class)).atPosition(i)
        .check(matches(withText(expectedItemText)));
}

Where the withItemCount matcher above is a simple matcher that asserts against the given adapter view's adapter count: 上面的withItemCount匹配器是一个简单的匹配器,它针对给定的适配器视图的适配器计数进行断言:

public static Matcher<View> withNumberOfItems(final int itemsCount) {
    return new BoundedMatcher<View, AdapterView>(AdapterView.class) {
        @Override
        public void describeTo(Description description) {
            description.appendText("with number of items: " + itemsCount);
        }

        @Override
        protected boolean matchesSafely(AdapterView item) {
            return item.getAdapter().getCount() == itemsCount;
        }
    };
}

I think the same concept should work for an action bar overflow menu. 我认为相同的概念应适用于操作栏溢出菜单。

I'm not clear what you mean by: 我不清楚您的意思是:

For both tests, I can write a check that ensures there is a view element with the correct "label" displayed (ie finding the view using onView(withText(this.elementText)). However I have 2 actions which have the same label but different IDs and I need to ensure the correct action is in the context menu/long click menu. 对于这两个测试,我都可以编写检查以确保显示的视图元素具有正确的“标签”(即使用onView(withText(this.elementText)查找视图))。但是,我有2个动作具有相同的标签,但不同的ID,我需要确保上下文菜单/长按菜单中的操作正确。

But the atPosition should get you exactly the view you're interested in the list, and you can add onChildView if you need to target as sub-view within a given item in the list. 但是atPosition应该可以为您提供您对列表感兴趣的视图,并且如果需要在列表中的给定项目中作为子视图定位,则可以添加onChildView

Hope that helps! 希望有帮助!

Thank you so much to dominicoder for pretty much giving me the answer to this question. 非常感谢dominicoder给我这个问题的答案。 working on their reply i have managed to get it working. 在他们的答复上工作,我设法使它起作用。

Instead of using "isAssignableFrom(AdapterView.class)" I use "isAssignableFrom(ListView.class)". 而不是使用“ isAssignableFrom(AdapterView.class)”,而是使用“ isAssignableFrom(ListView.class)”。

I then use the exact same matcher "dominicoder" provided to verify the context menu item count. 然后,我使用提供的完全相同的匹配器“ dominicoder”来验证上下文菜单项的数量。

Using "dominicoder's" sample matchers I was able to code one myself that checks the MenuItem at a certain position in the ListView and I can compare the IDs to make sure its the ID that I am expecting. 使用“ dominicoder的”样本匹配器,我自己编写了一个代码,用于检查ListView中某个位置的MenuItem,并且可以比较ID以确保其期望的ID。

public boolean verifyRowContextMenuContents(String name, MyActionObject[] actions){
    // invoke the row context menu
    clickRowActionButton(name);

    // The Context Menu Popup contains a ListView
    int expectedItemCount = actions.length;

    // first check the Popup's listView contains the correct number of items
    onView(isAssignableFrom(ListView.class))
            .check(matches(correctNumberOfItems(expectedItemCount)));

    // now check the order and the IDs of each action in the menu is the expected action
    for (int i = 0; i < expectedItemCount; i++) {
        onView(isAssignableFrom(ListView.class))
                .check(matches(correctMenuId(i, actions[i].getId())));
    }

    // close the context menu
    pressBack();

    return true;
}

private static Matcher<View> correctNumberOfItems(final int itemsCount) {
    return new BoundedMatcher<View, ListView>(ListView.class) {
        @Override
        public void describeTo(Description description) {
            description.appendText("with number of items: " + itemsCount);
        }

        @Override
        protected boolean matchesSafely(ListView listView) {
            ListAdapter adapter = listView.getAdapter();
            return adapter.getCount() == itemsCount;
        }
    };
}

private static Matcher<View> correctMenuId(final int position, final int expectedId) {
    return new BoundedMatcher<View, ListView>(ListView.class) {
        @Override
        public void describeTo(Description description) {
            description.appendText("with position : " + position + " expecting id: " + expectedId);
        }

        @Override
        protected boolean matchesSafely(ListView listView) {
            ListAdapter adapter = listView.getAdapter();
            Object obj = adapter.getItem(position);
            if (obj instanceof MenuItem){
                MenuItem menuItem = (MenuItem)obj;
                return menuItem.getItemId() == expectedId;
            }
            return false;
        }
    };
}   

With this code I can check the Context Menu contains the correct number of menu items, and that the items in the menu are the ones i am expecting (using ID verification) and the order I am expecting. 使用此代码,我可以检查上下文菜单是否包含正确数量的菜单项,并且菜单中的项是否是我期望的(使用ID验证)和期望的顺序。

Huge thank you to "dominicoder". 非常感谢“ dominicoder”。 Its a shame you can not mark both answers as correct as you did actually give me virtually the correct answer. 很遗憾您不能将两个答案都标记为正确答案,就像您实际上给了我正确答案一样。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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