我正在Espresso for Android中编写UI自动化测试。遇到了一个我到目前为止还没有得到任何解决方案的场景。
在一个Fragment
中,我OptionsMenu
只有一个项目。根据API响应的值设置MenuItem
的状态。
@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
。
点击overflowmenu,
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:找不到层次结构中的视图匹配:(带 text:is" Cancel Order"和id: com.equinix.ecp.betatest:ID / cancel_order)
所以我尝试将其更改为
onView(allOf(withText("Cancel Order"))).check(matches(not(isEnabled())));
不知何故,这与视图匹配,但它不是MenuItem,而是MenuItem&中的TextView。由于我将setEnabled()
设置为MenuItem,check()
断言因为TextView
而无法按预期工作。
所以我的问题是如何编写Test以检查MenuItem的启用/禁用状态。
答案 0 :(得分: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")
可能无效。
答案 1 :(得分:0)
最好使用uiautomatorviewer,在测试失败的位置插入一个断点,然后检查应用的布局以寻找线索
在我看来,您有两种看法。一个ID为R.id.cancel_order
,另一个ID为文本"Cancel Order"
,该文本可能具有另一个ID(或可能/应该)。
因此它们一起返回NoMatchingView,因为它们不是同一视图。
它们可能是同级视图,或者一个视图可能是另一个视图的后代。 uiautomatorviewer在这里很方便找出屏幕上发生的事情
只要已安装“ Android SDK平台工具”和“ Android SDK工具” 从终端:
cd /Users/<user name>/Library/Android/sdk/tools/bin
./uiautomatorviewer
(将其另存为脚本,并且为了方便起见仅使用别名快捷方式也很有帮助)
至于您的匹配者,我会尝试:
onView(allOf(
withId(R.id.cancel_order),
hasSibling(withText("Cancel Order"))
)).check(matches(not(isEnabled())));
或将hasSibling(_)
更改为hasDescendent(_)
或isDescendentOfA(_)
,具体取决于它们之间的关系(您可以使用uiautomatorviewer找出它们)