如何在Espresso UI自动化测试中检查MenuItem是否启用/禁用

9
我正在为Android编写Espresso UI自动化测试,并遇到了一个目前没有解决方案的情况。
在一个Fragment中,我有一个带有单个项的OptionsMenu。该MenuItem的状态根据API响应的值进行设置。
@Override
public void onPrepareOptionsMenu(Menu menu) {
    super.onPrepareOptionsMenu(menu);
    menu.clear();
    getActivity().getMenuInflater().inflate(R.menu.menu_cancel_order, menu);
    MenuItem cancelMenuItem = menu.findItem(R.id.cancel_order);
    if(something) { // something can be a boolean value from server
        cancelMenuItem.setEnabled(true);
    } else {
        cancelMenuItem.setEnabled(false);
    } 
}

对于UI测试,我需要编写测试用例来检查此MenuItem是否启用/禁用。

要点击溢出菜单,

ViewInteraction actionMenuItemView = onView(
            allOf(withId(R.id.action_settings), withContentDescription("Settings"), isDisplayed()));
actionMenuItemView.perform(click());

到目前为止,我尝试检查断言的结果如下。

onView(allOf(withText("Cancel Order"), withId(R.id.cancel_order))).check(matches(not(isEnabled())));

但是这会触发NoMatchingViewException错误,并显示以下信息:

NoMatchingViewException: 未找到匹配的视图层次结构:(文本为:“Cancel Order”,ID为:“com.equinix.ecp.betatest:id/cancel_order”)

因此,我尝试将其更改为

onView(allOf(withText("Cancel Order"))).check(matches(not(isEnabled())));

一些方式可以匹配视图,但它不是菜单项而是菜单项内的TextView。由于我正在为菜单项设置setEnabled(),因此check()断言不会像预期的那样工作,因为它是一个TextView。所以我的问题是如何编写测试来检查菜单项的启用/禁用状态。

1
你找到解决方法了吗?我也有同样的情况。 - makovkastar
1
@makovkastar 并不完全是如此。但我所做的是,而不是检查菜单项是否已启用/禁用,我只是执行菜单项的点击操作,并检查接下来页面上未显示的项目。因此,如果该项目未显示,则表示未执行单击,从而意味着菜单已禁用。虽然不完美,但目前就是我所做的。等待更完美的解决方案。 - Sujay
2个回答

2
使用uiautomatorviewer是个好主意,在测试失败的地方设置一个断点,然后检查你的应用程序布局以获取线索。
听起来你有两个视图。一个带有id为“R.id.cancel_order”,另一个文本为“Cancel Order”,它可能有另一个id(或者可以/应该有)。因此,它们一起返回NoMatchingView,因为它们不是同一个视图。
它们可能是兄弟视图,或者可能一个是另一个的后代。这就是uiautomatorviewer非常方便的地方,可以弄清屏幕上正在发生什么。
只要你已经安装了“Android SDK Platform-Tools”和“Android SDK Tools”
从终端:
cd /Users/<user name>/Library/Android/sdk/tools/bin
./uiautomatorviewer

"最初的回答"翻译成英文是 "Original Answer"。以下是需要翻译的内容:

(将此保存为脚本并使用别名快捷方式也很有帮助)

至于你的匹配器,我建议尝试:

onView(allOf(
    withId(R.id.cancel_order),
    hasSibling(withText("Cancel Order")) 
)).check(matches(not(isEnabled())));

或者将hasSibling(_)更改为hasDescendent(_)isDescendentOfA(_),具体取决于它们之间的关系(您可以使用uiautomatorviewer找出)。"Original Answer"翻译成"最初的回答"。

0
我建议您使用菜单项的ID来执行检查。 我尝试过这个菜单:
<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="at.hellobank.hellomarkets.symbols.DetailActivity">

<item
    android:id="@+id/action_1"
    android:icon="@android:drawable/arrow_down_float"
    android:title="Menu1"
    app:showAsAction="always" />

<item
    android:id="@+id/action_2"
    android:enabled="false"
    android:icon="@android:drawable/arrow_down_float"
    android:title="Menu2"
    app:showAsAction="always" />
</menu>

因此,一个菜单项是启用的,另一个菜单项是禁用的。我的测试检查如下,并按预期工作:

@Test
public void testMenuItemsStatus() throws Exception {
    onView(withId(R.id.action_1)).check(matches(isEnabled()));
    onView(withId(R.id.action_2)).check(matches(not(isEnabled())));
}

在我的看法中,通常在测试中使用ID更好,因为这样可以更独立于拼写错误和一般语言。如果您在另一种语言的应用程序中进行本地化测试,则withText("Cancel Order")可能无法正常工作。


谢谢您的回答。我已经尝试使用ID,但在那种情况下我得到了异常。此外,我的菜单项xml与您在答案中使用的略有不同。'action_settings'是主项ID,在其中我有一个带有id 'cancel_order'和showAsAction="ifRoom"的子菜单项。 - Sujay

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