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

时间:2016-11-20 11:38:01

标签: android android-espresso android-testing android-databinding

我在Android应用程序上运行Espresso测试。测试是片状的。它可以可靠地声明数据模型已更新。我的问题是ViewMatchers无法匹配View中的相同值,因为ViewDataBinding尚未更新Views。 (至少大部分时间都是测试运行。)

当ViewDataBinding在视图上没有挂起的更改时,是否会出现IdlingResource这样的事情?

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

的组合

2 个答案:

答案 0 :(得分:13)

Espresso在执行视图检查之前先进行waitForIdlewaitForIdle陷入IdlingRegistry的状态,并一直等到每个IdlingResource都处于空闲状态。

LoopingIdlingResource默认在Espresso中使用。它一直等待,直到循环器没有消息在队列中为止,这意味着它处于空闲状态。

然而,DataBinding使用不同的方法来计划更新,但它使用了Choreographer.postFrameCallback。因此,更新不会发布到循环器队列中,并且Espresso将不会等待它们。

在这种情况下,您应该注册自己的IdlingResource。您可以在googlesamples/android-architecture-components中找到不错的示例,了解如何实现自定义DataBindingIdlingResourceDataBindingIdlingResourceRule,这些自定义DataBindingIdlingResourceRuleDataBindingIdlingResource将在执行测试之前设置空闲资源。

因此,您必须将这些类{{3}}和{{3}}复制到测试中。

并将以下规则添加到测试类中:

@Rule
@JvmField
val dataBindingIdlingResourceRule = DataBindingIdlingResourceRule(activityRule)

答案 1 :(得分:3)

编辑:这是一个老答案。请使用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);
}

然后,只需为正在测试的活动定义ActivityTestRule,并覆盖其beforeActivityLaunched()。有必要在启动活动之前执行此操作(而不是@Before注释),因为ViewDataBinding如果不使用Looper将初始化CHOREOGRAPHER }。

@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()