浓缩咖啡点击菜单项

42

我在actionbar中有一个菜单,我是通过以下方式创建的:

@Override
public boolean onCreateOptionsMenu(Menu menu) {

    menu.add(Menu.NONE, 98,Menu.NONE,R.string.filter).setIcon(R.drawable.ic_filter_list_white_48dp).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
    menu.add(Menu.NONE, 99,Menu.NONE,R.string.add).setIcon(R.drawable.ic_add_white_48dp).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);


    getMenuInflater().inflate(R.menu.menu_main, menu);

    return true;
}

并且menu_main.xml看起来像:

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".MainActivity">
    <item
        android:id="@+id/action_settings"
        android:title="@string/action_settings"
        android:orderInCategory="100"
        app:showAsAction="never"
        android:icon="@drawable/ic_settings_white_48dp"/>
</menu>

我希望在Espresso测试中点击"add"图标(menuId为99)。我尝试了

@Test
public void testAdd() {
openActionBarOverflowOrOptionsMenu(InstrumentationRegistry.getTargetContext());
    onView(withText(R.string.add)).perform(click());
}
但是这会导致 NoMatchingViewException 错误。(我可以使用同样的代码点击在xml中直接定义的设置项。)
这是针对 targetSdkVersion 23 和 AppCompatActivity 的。工具栏的相关行为:
Toolbar toolbar = (Toolbar) findViewById(R.id.tool_bar);
setSupportActionBar(toolbar);
if( getSupportActionBar() != null ) {
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}

而 tool_bar.xml 的外观如下:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar     xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:theme="@style/ThemeOverlay.AppCompat.Dark"
    android:background="@color/ColorPrimary"
    android:elevation="4dp"
    tools:ignore="UnusedAttribute">
</android.support.v7.widget.Toolbar>

1
你使用的是什么targetSdkVersion、ActionBar和设备/模拟器?请查看openActionBarOverflowOrOptionsMenu()实现(Espresso类),它取决于这些因素。我需要调查一下,但是根据我使用的模拟器,有些地方出了问题。 - albodelu
targetSdkVersion 23 和 AppCompatActivity。我在上面添加了工具栏代码。 - user1583209
当使用"withText(R.string.add)"与文本进行匹配时,是否可能存在问题,因为实际的文本不可见,只有图标(R.drawable.ic_add_white_48dp)可见? - user1583209
这是在索尼Xperia SP上(真实设备,而非模拟器)的情况。 - user1583209
不是解决方案,但我注意到“onView(withId(99)).perform(click());”可以工作,尽管我记得在某个地方读到过那些“menu-Id”与“view-id”不同... - user1583209
我删除了我的评论,因为我没有看到行末的最终内容,这改变了它,很抱歉。我会将它们分开,以便像我这样的其他人可以看到它。 - albodelu
7个回答

57
更新:我没有看到行末的最后部分,请忽略我的先前回答,我试图快速修复它,但却做错了。我真的不知道答案。
...setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)

您的问题在这里由Espresso团队进行了解释:https://google.github.io/android-testing-support-library/docs/espresso/advanced/#matching-a-view-that-is-inside-an-actionbar

匹配可见图标:

  // Click on the icon - we can find it by the r.Id.
  onView(withId(R.id.action_save))
    .perform(click());

对于普通操作栏,点击溢出菜单中的项目有点棘手,因为一些设备有一个硬件溢出菜单按钮(它们将在选项菜单中打开溢出的项目),而一些设备有一个软件溢出菜单按钮(它们将打开一个普通的溢出菜单)。幸运的是,Espresso 已经为我们处理了这个问题。

  // Open the overflow menu OR open the options menu,
  // depending on if the device has a hardware or software overflow menu button.
  openActionBarOverflowOrOptionsMenu(getInstrumentation().getTargetContext());

  // Click the item.
  onView(withText("World"))
    .perform(click());

所以我理解两种替代方案都是正确的,但取决于具体情况。如果你测试一个按钮,通常会知道它此时是否可见。

在你的情况下,由于有空间,该按钮是可见的,因此像这里一样使用withId是正确的:

import static android.support.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu;

@Test
public void testClickInsertItem() {
    openActionBarOverflowOrOptionsMenu(InstrumentationRegistry.getTargetContext());
    onView(withId(R.id.action_insert)).perform(click());
}

这个方法对于溢出项目也是正确的:

  

是的,在Espresso中就是这样工作的。问题在于,Android中表示菜单项的View没有菜单项的ID。所以onView(withId(X))无法找到一个视图而失败了。我没有更好的建议,只能使用withText()。如果您有多个具有相同文本的视图,则可以使用层次结构进行区别。

现在我的问题是,在不同设备上测试时,当有一个项目的空间时,您该怎么办。我不知道答案,也许将两种解决方案结合起来。


谢谢。所以使用“withText()”匹配可见图标是不可能的吗?如果可能的话,我想尽可能避免使用“withId()”,因为在我的理解中,测试应该模拟用户操作,而人类会寻找文本/图标而不是(不可见的)ID。 - user1583209
我不知道,等更好的回答吧。之前我回答了是因为我以为这个问题和我评论的一样。如果没有人回答并且我找到了更好的答案,我会更新的。我从来没有使用过SHOW_AS_ACTION_IF_ROOM,而且我还在学习Espresso。 - albodelu

7
这是我的解决方案,涵盖了三种情况:硬件菜单按钮、溢出菜单和仅图标:
    try {
        openActionBarOverflowOrOptionsMenu(InstrumentationRegistry.getTargetContext());
    } catch (Exception e) {
        //This is normal. Maybe we dont have overflow menu.
    }
    onView(anyOf(withText(R.string.<your label for the menu item>), withId(R.id.<id of the menu item>))).perform(click());

6

使用此功能可匹配菜单项描述文本:

onView(withContentDescription(R.string.add)).perform(click());

那么,您无需匹配(不存在的)ID或可绘制图标。

此外,请记住,如果您需要确保菜单已展开,请使用Espresso文档中的此代码段

// Open the overflow menu OR open the options menu,
// depending on if the device has a hardware or software overflow menu button.
openActionBarOverflowOrOptionsMenu(getInstrumentation().getTargetContext());

这是所有情况下 withText() 不适用的最佳解决方案!它还可用于仅包含图标项(app:showAsAction="always")。只需添加 <item ...android:contentDescription="@string/R.string.add" 并使用 withContentDescription(R.string.add) - allofmex

5

不要让自己承受太多,让我们简化它

onView(withId(98)).perform(click());

这将帮助您执行“添加”按钮的点击操作。

我知道这一点。但我更喜欢匹配“withText()”。另请参见我对albodelu答案的评论。 - user1583209
使用Text不适用于此场景,因为Espresso基本上查找屏幕上显示的文本。然而,我们使用的是没有任何文本的图标。我们无法使用Text()执行操作。 - Manish

4
您可以使用此方法点击菜单项。首先,使用以下代码单击菜单按钮
openActionBarOverflowOrOptionsMenu(getInstrumentation().getTargetContext());

然后根据文本执行点击菜单项。将你的菜单项名称替换为"MenuItemName"。

onView(withText("MenuItemName")).perform(click());

1
Espresso.openContextualActionModeOverflowMenu() 

对于我的三星Note 3,这是唯一有效的选择。这个openActionBarOverflowOrOptionsMenu(getInstrumentation().getTargetContext());会尝试并失败,但没有任何错误提示。


-1
工具栏不是操作栏,不需要调用:
openActionBarOverflowOrOptionsMenu(InstrumentationRegistry.getTargetContext());

如果这样做,那么您的项目肯定不会在那里找到(它不在 ActionBar 中),而 ToolBar 属于“常规视图”。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接