如何让 Espresso 等到数据绑定用数据模型更新了视图?

How do I make Espresso wait until Data Binding has updated the View with the data-model?

我正在 运行 对我的 Android 应用程序进行 Espresso 测试。测试很不稳定。它可以可靠地断言数据模型已更新。我的问题是 ViewMatchers 无法匹配视图中的相同值,因为 ViewDataBinding 尚未更新视图。 (至少大部分时间测试运行。)

当 ViewDataBinding 在视图上没有未决更改时,是否存在 IdlingResource 之类的东西变为空闲?

我的解决方法是结合调用 executePendingBindings() 和一个小 Thread.sleep(...)

编辑:这是一个旧答案。请使用 Roshak 的

错误报告中提到使用反射将 ViewDataBinding.USE_CHOREOGRAPHER 更改为 false 以进行测试,所以这是我想出的解决方案:

public static void setFinalStatic(Field field, Object newValue) throws Exception {
    field.setAccessible(true);

    Field modifiersField;
    try {
        modifiersField = Field.class.getDeclaredField("accessFlags");
    } catch(NoSuchFieldException e) {
        //This is an emulator JVM  ¯\_(ツ)_/¯
        modifiersField = Field.class.getDeclaredField("modifiers");
    }
    modifiersField.setAccessible(true);
    modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

    field.set(null, newValue);
}

然后,为被测Activity定义一个ActivityTestRule,并覆盖它的beforeActivityLaunched()。有必要在启动 activity 之前执行此操作(而不是在 @Before 注释中),因为 ViewDataBinding 如果不使用 [=] 将初始化 Looper 19=].

@Override
protected void beforeActivityLaunched() {
    super.beforeActivityLaunched();
    //Because we are using data-binding, we avoid using CHOREOGRAPHER
    try {
        ReflectionUtils.setFinalStatic(
           ViewDataBinding.class.getDeclaredField("USE_CHOREOGRAPHER"), false);
    } catch (Exception e) {
        Assert.fail(e.getMessage());
    }
}

这样,你就可以摆脱那个Thread.sleep()

Espresso 在执行视图检查之前 waitForIdlewaitForIdle 思考 IdlingRegistry 并等待每个 IdlingResource 空闲。

LoopingIdlingResource 默认用于 Espresso。它一直等到 looper 队列中没有消息,这意味着它是空闲的。

但是 DataBinding 使用不同的方法来安排更新,它使用 Choreographer.postFrameCallback。因此更新不会发布到循环队列中,Espresso 也不会等待它们。

在这种情况下,您应该注册自己的 IdlingResource. You can find in googlesamples/android-architecture-components nice sample how to implement custom DataBindingIdlingResource and DataBindingIdlingResourceRule,这将在执行测试之前设置空闲资源。

因此您必须将这些 classes DataBindingIdlingResourceRule and DataBindingIdlingResource 复制到您的测试中。

并将以下规则添加到您的测试中 class:

@Rule
@JvmField
val dataBindingIdlingResourceRule = DataBindingIdlingResourceRule(activityRule)