gpt4 book ai didi

android - 使用 Espresso 的异步 UI 单元测试,IdlingResource 因竞争条件而失败

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:35:58 25 4
gpt4 key购买 nike

我正在尝试将我的一些 Robotium 单元测试转换为使用 Espresso,但在通过测试更新 UI 时遇到了问题。该测试针对的是一个 fragment ,该 fragment 是一种显示来自对象的数据的表单。该 fragment 有一个方法“BaseFragment.object_set(object)”,然后它将更新 UI 组件(有很多 TextView.setText(object.getField())) .

当我在测试中运行以下命令时...

BaseFragment fragment = (BaseFragment) getFragment(activity);
fragment.object_set(object);
assertNotNull(fragment.object_get());

...我得到这个异常...

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

当我改为运行它时...

activity.runOnUiThread(new Runnable() {
public void run() {
BaseFragment fragment = (BaseFragment) getFragment(activity);
fragment.object_set(object);
}
});
sleep(500);
assertNotNull(fragment.object_get());

...测试成功。如果没有 sleep(),它实际上会因竞争条件而失败。

因此,我的理解是 Espresso 的 sleep 是一种糟糕的形式,我们应该实现并注册一个 Idling 资源。我试过这个...

 sEspressoIdlingResource.setNotIdle();
activity.runOnUiThread(new Runnable() {
public void run() {
BaseFragment fragment = (BaseFragment) getFragment(activity);
fragment.object_set(object);
sEspressoIdlingResource.setIdle();
}
});

...在调试时我可以看到 Espresso 实际上正在等待资源释放...只是这仍然会导致竞争条件,测试失败。看起来 UI 直到 AFTER activity.runOnUiThread() 完成后才更新,所以我想我只是不明白哪个线程是哪个的原则......有人可以帮忙吗并解释一下?

下面是一些重要的测试代码(下面的测试会由于竞争条件而失败)...

@RunWith(AndroidJUnit4.class)
public class MyTest{

ActivityTestRule<AMain> mActivityTestRule;

@Rule
public ActivityTestRule<AMain> setUp() {
// other code here
mActivityTestRule = new ActivityTestRule<>(AMain.class);
return mActivityTestRule;
}

@Before
public void before() {
Espresso.registerIdlingResources(BaseTest.sEspressoIdlingResource);
}

@After
public void after() {
Espresso.unregisterIdlingResources(BaseTest.sEspressoIdlingResource);
}

@Test
public void test_1_showDetailsFragment() {
// more code here for activity and object
sEspressoIdlingResource.setNotIdle();
activity.runOnUiThread(new Runnable() {
public void run() {
BaseFragment fragment = (BaseFragment) getFragment(activity);
fragment.object_set(object);
sEspressoIdlingResource.setIdle();
}
});
assertNotNull(fragment.object_get());
// more asserts here
}
}

最佳答案

你现在可能已经自己回答了这个问题,但我相信我也有类似的问题,那就是 Espresso 没有等待 :

activity.runOnUiThread(new Runnable{...})

在执行其操作之前要完成的代码。(就我而言):

onView(withId(R.id.where_city_search_input)).perform(typeText("Ch"));

据我所知,espresso 在执行其操作之前等待主线程处于空闲状态。所以如果你:

  1. 定义一个可运行的:

    Runnable myRunnable = new Runnable{...};
  2. 告诉 Instrumentation 等待这个 Runnable:

    InstrumentationRegistry.getInstrumentation().waitForIdle(myRunnable);

然后运行任何你想要的 Espresso 代码就可以了。最后它应该看起来像这样:

// Define Runnable:
Runnable myRunnable = new Runnable(){
@Override
public void run(){
// What you want to run //
}
};
// Run on UI Thread:
activity.runOnUiThread(myRunnable);
// Tell Instrumentation to wait:
InstrumentationRegistry.getInstrumentation().waitForIdle(myRunnable);

// BEGIN ESPRESSO CODE //
................
// END ESPRESSO CODE //

关于android - 使用 Espresso 的异步 UI 单元测试,IdlingResource 因竞争条件而失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34388098/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com