简体   繁体   English

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

[英]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很好的示例如何实现自定义DataBindingIdlingResourceDataBindingIdlingResourceRule ,它将在执行测试之前设置空闲资源。

So you have to copy these classes DataBindingIdlingResourceRule and DataBindingIdlingResource into your tests. 因此,您必须将这些类DataBindingIdlingResourceRuleDataBindingIdlingResource复制到您的测试中。

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.

相关问题 如何使其等到函数返回? 安卓系统 - How do I make it wait until a function has returned? Android 如何等待回调具有数据? - How to wait until Callback has data? 如何等待 Preferences DataStore 中的数据加载完毕? - How do I wait until data from Preferences DataStore is loaded? 等到加载视图后,再将加载的数据放入其中 - Wait until a View is loaded and then put loaded data in it 如何让我的应用程式等到AsyncTask完成工作再继续执行其他工作(Android) - How do I make my app wait until AsyncTask has finished its work before moving on to other tasks (Android) 我如何等待数据写入文件? - How can i wait until the data is written to file? 如何使Espresso测试继续进行,而不等待asynctask完成? - How can I make Espresso test continue and NOT wait for an asynctask to complete? Espresso UI 测试,无法检查加载 state,如何使用实时数据测试 UI 并查看 model? - Espresso UI Testing, Cannot check loading state, How to test UI with live data and view model? 是否可以使用 Espresso 的 IdlingResource 等待某个视图出现? - Is it possible to use Espresso's IdlingResource to wait until a certain view appears? 测试RecyclerView是否包含Espresso数据 - Testing RecyclerView if it has data with Espresso
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM