[英]How do I make Espresso wait until Data Binding has updated the View with the data-model?
I am running Espresso tests on my Android application. 我正在Android应用程序上运行Espresso测试。 The test is flaky. 测试是片状的。 It can reliable assert that the data-model is updated. 它可以可靠地声明数据模型已更新。 My problem is that the ViewMatchers can't match the same value in the View because the ViewDataBinding has not yet updated the Views. 我的问题是ViewMatchers无法匹配View中的相同值,因为ViewDataBinding尚未更新Views。 (At least most of the time the test runs. ) (至少大部分时间都是测试运行。)
Is there such a thing as an IdlingResource that becomes idle when the ViewDataBinding has no pending changes on the view? 当ViewDataBinding在视图上没有挂起的更改时,是否会出现IdlingResource这样的事情?
My work-around is a combination of calling executePendingBindings() and a small Thread.sleep(...) 我的解决方法是调用executePendingBindings()和一个小的Thread.sleep(...)的组合。
Espresso does waitForIdle
before executing view checks. Espresso在执行视图检查之前执行waitForIdle
。 waitForIdle
goes thought IdlingRegistry
and waits until every IdlingResource
is idle. waitForIdle
认为是IdlingRegistry
并等待,直到每个IdlingResource
都空闲。
LoopingIdlingResource
is used in Espresso by default. 默认情况下,在Espresso中使用LoopingIdlingResource
。 It waits until looper doesn't have messages in queue, which means that it is idle. 它一直等到looper队列中没有消息,这意味着它是空闲的。
However DataBinding
uses different approach to schedule an update, it uses Choreographer.postFrameCallback
. 但是, DataBinding
使用不同的方法来安排更新,它使用Choreographer.postFrameCallback
。 So updates are not posted into looper queue and Espresso will not wait for them. 所以更新不会发布到looper队列中,Espresso也不会等待它们。
In such cases you should register your own IdlingResource
. 在这种情况下,您应该注册自己的IdlingResource
。 You can find in googlesamples/android-architecture-components
nice sample how to implement custom DataBindingIdlingResource
and DataBindingIdlingResourceRule
that will sets the idle resource before executing tests. 你可以在googlesamples/android-architecture-components
很好的示例如何实现自定义DataBindingIdlingResource
和DataBindingIdlingResourceRule
,它将在执行测试之前设置空闲资源。
So you have to copy these classes DataBindingIdlingResourceRule
and DataBindingIdlingResource
into your tests. 因此,您必须将这些类DataBindingIdlingResourceRule
和DataBindingIdlingResource
复制到您的测试中。
And add the following rule into your test class: 并将以下规则添加到您的测试类中:
@Rule
@JvmField
val dataBindingIdlingResourceRule = DataBindingIdlingResourceRule(activityRule)
Edit : This is an old answer. 编辑 :这是一个老答案。 Please use Roshak's 请使用Roshak's
The bug report mentioned using reflection to change ViewDataBinding.USE_CHOREOGRAPHER
to false
for the tests, so here is the solution I came up with: 错误报告提到使用反射将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);
}
Then, just define an ActivityTestRule
for the Activity under test, and override its beforeActivityLaunched()
. 然后,只为正在测试的Activity定义一个ActivityTestRule
,并覆盖它的beforeActivityLaunched()
。 It is necessary to do this before the activity is launched (as opposed to in a @Before
annotation) because ViewDataBinding
will initialize a Looper
if it doesn't use CHOREOGRAPHER
. 在启动活动之前必须执行此操作(而不是在@Before
注释中),因为如果不使用CHOREOGRAPHER
ViewDataBinding
将初始化Looper
。
@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());
}
}
This way, you can get rid of that Thread.sleep()
这样,你可以摆脱Thread.sleep()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.