Espresso:在对话框下匹配视图

3

我的测试用例非常简单:在主活动视图中,我有一个抽屉。这个抽屉里有一个菜单项可以打开对话框。我想要验证当点击这个菜单项时,在打开对话框之前,抽屉已经关闭了。

以下是我现在拥有的:

// 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,因为抽屉似乎不再是视图层次结构中的组件了。看起来显示对话框会使其成为视图层次结构的新根。尽管如此,我知道活动视图仍然存在。我想知道,在这种情况下,如何匹配对话框下方的视图。
1个回答

4

这是一个非常好的问题,我很惊讶为什么在其他地方没有被提出或讨论。

你的推理是正确的,当对话框出现时,视图层次结构会发生改变,因此 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种不同的方法可以获取活动实例。这个方法是从获取活动实例中获取的)

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];
  }

作为个人偏好,除非需要测试某些非常重要且没有其他测试方式的内容,我不太喜欢使用活动实例。

谢谢!它运行良好。希望这种用例在未来的版本中会被考虑进去。 - Augier

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