如何编写在运行时确定视图内容的 Android UI 测试?

How to write an Android UI test where the contents of views are determined at runtime?

情况

我正在编写一个 timetable-viewing 应用程序,要实现的第一个功能是选择要查看时间表的课程。

用户从列表中选择他们的课程名称,然后转到另一个屏幕以进一步指定他们当前所在课程的年份、组别等。用于选择课程和编辑课程的屏幕详情如下:


目标

受到Google I/O 17 talk on Test-Driven Development on Android的启发,我想写一个UI测试用例来测试这个特性。具体来说,我希望我的测试能够确认,如果用户单击其中一个课程名称,他们将被带到 'edit course details' 屏幕,并且课程标题位于顶部,例如'Accounting and Finance' 与在列表中单击的匹配。


问题

使用 Espresso 的测试,对于选择标题为 'Accounting and Finance' 的课程并查看下一个屏幕上是否显示正确标题的特定情况,看起来(大致)如下所示:

@Test
public void chooseCourse() {
    onView(withId(R.id.rv_course_list))
            .perform(RecyclerViewActions.actionOnItemAtPosition(
                    /*Somehow find position of Accounting and Finance*/,
                    click())
            );


    onView(withId(R.id.course_title))
            .check(matches(withText("Accounting and Finance")))
            .check(matches(isDisplayed()));
}

我的问题是 RecyclerView 课程列表将在运行时使用来自 HTTP 请求或 SQLite 数据库的结果填充,并且无法事先知道该列表是否包含 'Accounting and Finance'或其他(我不希望测试失败只是因为应用程序运行时特定课程不在列表中)。

考虑到这一点,我无法hard-code将课程名称纳入测试。请注意,我不是要编写单元测试,我只是模拟获取课程列表的依赖性以确保 'Accounting and Finance' 在列表中(并且会可能只是隔离 ChooseCourseActivity class,捕获它的 Intents)。

在我上面链接的视频中,演示者通过 UI 测试笔记应用程序的 add-note 功能,测试如下:

  1. 单击 'add note' 按钮
  2. 输入笔记的标题和描述
  3. 单击 'save note' 按钮
  4. 验证列表中是否包含包含步骤 2 中的详细信息的新注释

在那种情况下 hard-coding 用于查找视图的文本(标题和描述)效果很好,因为测试中的代码 确定 视图的内容,即笔记列表中的笔记。在我的例子中,视图的内容将由 HTTP 响应或数据库查询决定


问题

编辑:这个问题最好的解决方案似乎是所谓的'hermetic testing'和this blog描述了如何将它应用到android UI.

您可以通过几种不同的方式对此进行测试,我在我的应用程序中使用了所有这些方式的组合。

1) 您可以按照您的建议模拟 network/database 图层。

2) 您可以在测试中调用 API 以获取 'expected' 数据集,然后验证它是否正确显示在 UI.

3) 您可以存根您的网络层以允许您注入已知数据而不依赖于您的网络端点。 Retrofit 尤其让这件事变得非常容易。

4) 您可以使用不会经常更改的已知测试数据集针对实时端点进行测试。

我倾向于将 Espresso 用于 UI 水平测试和全面回归测试。在 UI 级别测试中,我将 networking/on 设备持久层存根,并使用我在测试期间注入的数据集测试客户端。对于回归测试,我关心测试与我的 API 的集成,对于那些我使用已知不变数据的测试帐户。