如何让 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 在执行视图检查之前 waitForIdle
。 waitForIdle
思考 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)
我正在 运行 对我的 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 在执行视图检查之前 waitForIdle
。 waitForIdle
思考 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)