I'm trying to convert some of my Robotium UnitTests to use Espresso and have a problem when updating the UI through the test. The test is for a fragment that is a form displaying data from an object. The fragment has a method 'BaseFragment.object_set(object)', which will then update the UI components (with lots of TextView.setText(object.getField())).
When I run the following inside my test...
BaseFragment fragment = (BaseFragment) getFragment(activity);
fragment.object_set(object);
assertNotNull(fragment.object_get());
...I get the this exception...
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
When I run this instead...
activity.runOnUiThread(new Runnable() {
public void run() {
BaseFragment fragment = (BaseFragment) getFragment(activity);
fragment.object_set(object);
}
});
sleep(500);
assertNotNull(fragment.object_get());
...the test succeeds. Without the sleep() it actually fails for a race condition.
So, my understanding is that sleep is bad form with Espresso, and that we're supposed to implement and register an Idling resource. I tried this one...
sEspressoIdlingResource.setNotIdle();
activity.runOnUiThread(new Runnable() {
public void run() {
BaseFragment fragment = (BaseFragment) getFragment(activity);
fragment.object_set(object);
sEspressoIdlingResource.setIdle();
}
});
...and when debugging I can see that Espresso is actually waiting for that resource to release... it's only that this will still lead to a race condition, failing the test. It also looks like the UI isn't being updated until AFTER activity.runOnUiThread() has finished, so I think I'm just not getting the principle of which thread is which... can someone help and explain?
Below some of the test code if it matters (the test below would fail due to the race condition)...
@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
}
}
Aucun commentaire:
Enregistrer un commentaire