我的测试用例非常简单:在主活动视图上,我有一个抽屉。此抽屉中的一个菜单项将打开一个对话框。我想断言,单击此菜单项,然后在打开对话框之前关闭抽屉。
这里是我现在所拥有的:
// Opens the drawer
onView(withId(R.id.activity_main_navigation_drawer)).perform(DrawerActions.open())
// Check that the drawer is opened
onView(withId(R.id.activity_main_navigation_drawer)).check(matches(isOpen()))
// Click on the menu item that closes the drawer and display the dialog
onView(withText(R.string.title_add_subscription)).perform(click())
// Check that the drawer is now closed: this won't work
onView(withId(R.id.activity_main_navigation_drawer)).check(matches(isClosed()))
注意我还不想关闭对话框。因为目标是断言在显示对话框之前/期间已关闭抽屉。
问题是最后一条指令将升起NoMatchingViewException
,因为抽屉似乎不再处于视图层次结构中。看起来好像显示对话框使它成为视图层次结构的新根。不过,我知道活动视图存在于某处。在这种情况下,我想知道如何在显示对话框时匹配vie。
这是一个非常好的问题,令我惊讶的是,之前从未有人问过/讨论过它。
您的推论是正确的,当对话框出现时,视图层次结构发生更改,因此onView(withId(R.id.activity_main_navigation_drawer))
提供NoMatchingViewException。另外,在打开对话框之前将其分配给ViewInteraction
对象无济于事,因为Espresso会尝试使用新的视图层次结构来匹配对象,即使您想使用旧的对象(使用旧的视图层次结构来匹配)也是如此] >
我将建议的解决方案应该为您服务,据我所知,这是实现您想要的唯一方法。这有点违背UI测试的精神,因为我们只想模仿用户的动作并尝试以用户看到系统的方式声明事物,但我认为这种解决方案仍然可以,因为我们没有使用系统代码与系统进行交互。 (我们仅使用它来声明某些内容)
Activity activity = getActivityInstance(); DrawerLayout drawerLayout=(DrawerLayout) activity.findViewById((R.id.drawerlayout)); // your test code assertFalse(drawerLayout.isDrawerOpen(GravityCompat.START)) // your remaining test code
getActivityInstance
的方法(有超过999999种不同的方法来获取活动实例。该方法取自get activity instance
private Activity getActivityInstance(){ final Activity[] currentActivity = {null}; getInstrumentation().runOnMainSync(new Runnable(){ public void run(){ Collection<Activity> resumedActivity = ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(Stage.RESUMED); Iterator<Activity> it = resumedActivity.iterator(); currentActivity[0] = it.next(); } }); return currentActivity[0]; }
作为个人喜好,我不喜欢使用活动的实例,除非它是要测试非常重要的东西,而我真的不能以其他任何方式对其进行测试。