Android Expresso 正在验证上下文菜单和 actionBar 项目
Android Expresso verifying Context Menu and actionBar items
我有一个列表,其中每一行都包含一个名称和一个调用选项上下文菜单的按钮。我想编写一个测试来验证以下内容
- 上下文菜单包含正确的 NUMBER 个项目
- 上下文菜单包含正确的值
- 上下文菜单不包含任何不需要的选项(上面的检查 1 和 2 将测试这种情况)
我也想测试一下长选item时actionBar和actionBar溢出菜单的内容
对于这两个测试,我可以写一个检查来确保有一个视图元素显示了正确的 "label"(即使用 onView(withText(this.elementText) 查找视图)。但是我有 2 个具有相同标签但不同 ID 的操作,我需要确保上下文中的操作正确 menu/long 单击菜单。
我无法将我在 XML 中指定的 ID 用于上下文菜单的菜单,因为 Android 的上下文菜单视图没有这些 ID,而是包含内部 Android ID(见下面的截图)。
当我使用 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;
}
有谁知道如何使用 Expresso 获取上下文行菜单项的列表。
有谁知道如何使用 Expresso 获取 actionBar 项目(包括溢出菜单中的所有项目)?
如果我正确理解你的问题,你应该能够使用 onData() 方法与上下文菜单交互,因为它们只是 AdapterViews
(从你的屏幕截图中注意弹出窗口是ListPopupWindow$DropDownListView
).
所以你应该可以这样做:
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)));
}
上面的 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;
}
};
}
我认为同样的概念应该适用于操作栏溢出菜单。
我不太清楚你的意思:
For both tests, I can write a check that ensures there is a view
element with the correct "label" displayed (i.e 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.
但是 atPosition
应该让您准确地找到您对列表感兴趣的视图,如果您需要将目标定位为列表中给定项目中的子视图,您可以添加 onChildView
列表。
希望对您有所帮助!
非常感谢 dominicoder 给了我这个问题的答案。正在处理他们的回复,我已经设法让它工作了。
我没有使用 "isAssignableFrom(AdapterView.class)",而是使用 "isAssignableFrom(ListView.class)"。
然后我使用提供的完全相同的匹配器 "dominicoder" 来验证上下文菜单项计数。
使用 "dominicoder's" 示例匹配器,我能够自己编写一个代码来检查 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;
}
};
}
使用此代码,我可以检查上下文菜单包含正确数量的菜单项,并且菜单中的项目是我期望的(使用 ID 验证)和我期望的顺序。
非常感谢 "dominicoder"。很遗憾你不能将两个答案都标记为正确,因为你实际上给我了几乎正确的答案。
我有一个列表,其中每一行都包含一个名称和一个调用选项上下文菜单的按钮。我想编写一个测试来验证以下内容
- 上下文菜单包含正确的 NUMBER 个项目
- 上下文菜单包含正确的值
- 上下文菜单不包含任何不需要的选项(上面的检查 1 和 2 将测试这种情况)
我也想测试一下长选item时actionBar和actionBar溢出菜单的内容
对于这两个测试,我可以写一个检查来确保有一个视图元素显示了正确的 "label"(即使用 onView(withText(this.elementText) 查找视图)。但是我有 2 个具有相同标签但不同 ID 的操作,我需要确保上下文中的操作正确 menu/long 单击菜单。
我无法将我在 XML 中指定的 ID 用于上下文菜单的菜单,因为 Android 的上下文菜单视图没有这些 ID,而是包含内部 Android ID(见下面的截图)。
当我使用 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;
}
有谁知道如何使用 Expresso 获取上下文行菜单项的列表。
有谁知道如何使用 Expresso 获取 actionBar 项目(包括溢出菜单中的所有项目)?
如果我正确理解你的问题,你应该能够使用 onData() 方法与上下文菜单交互,因为它们只是 AdapterViews
(从你的屏幕截图中注意弹出窗口是ListPopupWindow$DropDownListView
).
所以你应该可以这样做:
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)));
}
上面的 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;
}
};
}
我认为同样的概念应该适用于操作栏溢出菜单。
我不太清楚你的意思:
For both tests, I can write a check that ensures there is a view element with the correct "label" displayed (i.e 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.
但是 atPosition
应该让您准确地找到您对列表感兴趣的视图,如果您需要将目标定位为列表中给定项目中的子视图,您可以添加 onChildView
列表。
希望对您有所帮助!
非常感谢 dominicoder 给了我这个问题的答案。正在处理他们的回复,我已经设法让它工作了。
我没有使用 "isAssignableFrom(AdapterView.class)",而是使用 "isAssignableFrom(ListView.class)"。
然后我使用提供的完全相同的匹配器 "dominicoder" 来验证上下文菜单项计数。
使用 "dominicoder's" 示例匹配器,我能够自己编写一个代码来检查 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;
}
};
}
使用此代码,我可以检查上下文菜单包含正确数量的菜单项,并且菜单中的项目是我期望的(使用 ID 验证)和我期望的顺序。
非常感谢 "dominicoder"。很遗憾你不能将两个答案都标记为正确,因为你实际上给我了几乎正确的答案。