如何使Espresso等到Data Binding使用数据模型更新View?

Ren*_*ene 11 android android-testing android-espresso android-databinding

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

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

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

Ros*_*hak 17

Espresso waitForIdle在执行视图检查之前执行.waitForIdle思考IdlingRegistry并等待,直到每个人IdlingResource都闲着.

LoopingIdlingResource默认情况下在Espresso中使用.它一直等到looper队列中没有消息,这意味着它是空闲的.

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

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

所以,你必须复制这些类DataBindingIdlingResourceRuleDataBindingIdlingResource到你的测试.

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

@Rule
@JvmField
val dataBindingIdlingResourceRule = DataBindingIdlingResourceRule(activityRule)
Run Code Online (Sandbox Code Playgroud)

  • 我们正在https://github.com/android/android-test/issues/317中跟踪对此的更好解决方案 (2认同)

ver*_*loc 5

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

该bug报告中提到使用反射来改变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);
}
Run Code Online (Sandbox Code Playgroud)

然后,只需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());
    }
}
Run Code Online (Sandbox Code Playgroud)

这样你就可以摆脱它 Thread.sleep()