如何使用 Espresso 测试 android activity 的保存和恢复状态?

How to test saving and restoring state of an android activity with Espresso?

有没有办法以编程方式测试 activity 的保存和恢复状态代码?我的意思是这样做:

How to test code built to save/restore Lifecycle of an Activity? 但以自动方式。

我测试了 activity.recreate() 方法,这几乎是我正在搜索的方法,但实际上它并没有重置我的 activity 的字段,就像我正在终止进程一样。所以即使我没有在我的 onCreate 方法中实现恢复,我的测试也可以通过(因为我的字段没有改变......)。

我目前正在玩 Espresso v2,我想知道这是否可能通过玩 InstrumentationRegistry.getInstrumentation() ?

您可以旋转屏幕并验证状态是否已正确保存和恢复。

private void rotateScreen() {
  Context context = InstrumentationRegistry.getTargetContext();
  int orientation 
    = context.getResources().getConfiguration().orientation;

  Activity activity = activityRule.getActivity();
  activity.setRequestedOrientation(
      (orientation == Configuration.ORIENTATION_PORTRAIT) ?
          ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE : 
          ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}

完整示例:http://blog.sqisland.com/2015/10/espresso-save-and-restore-state.html

解决方案是使用 activity.recreate() 方法,但不要忘记在后面加上一个等待空闲状态的断言。 我第一次尝试的问题是我写的测试是这样的:

instrumentation.runOnMainSync(new Runnable() {
    @Override
    public void run() {
        activity.recreate();
    }
});
assertThat(activityTestRule.getActivity().getXXX()).isNull();

其中 XXX 是一个字段,我希望在未实现 save/restore 状态处理时为空。但事实并非如此,因为我的断言不是等待娱乐任务完成。

所以在我的情况下,当我简单地添加一个 espresso 断言来完成工作时,我的问题就解决了,例如通过验证显示 XXX 字段的 TextView 是否为空。

最后,感谢 Espresso 提供的 UI 线程同步,我的测试可以断言我的 activity save/restore 状态缺失实现可以这样写:

instrumentation.runOnMainSync(new Runnable() {
    @Override
    public void run() {
        activity.recreate();
    }
});
onView(withText("a string depending on XXX value")).check(doesNotExist());

请注意,建议的旋转解决方案也可以完成这项工作,但当我们只想测试 activity 生命周期时,它可能比 activity.recreate() 慢得多。在我的例子中,它是不相关的,因为我的 activity 没有实现横向。

Android 提供的测试工具现在提供了一种编写 UI 测试的方法,可以重新创建 activity 来测试保存和恢复流程。请参阅 Recreate the activity section within the Test your app's activities Android 开发人员文档页面。语法示例(取自该页面)如下:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEvent() {
        val scenario = launchActivity<MyActivity>()
        scenario.recreate()
    }
}