Asynchronous UI Unittest with Espresso, IdlingResource does not work with race condition

I am trying to convert some of my Robotium UnitTests tests to use Espresso and have problems updating the user interface through the test. The test is intended for a fragment, which is a form that displays data from an object. The fragment has the method "BaseFragment.object_set (object)", which then updates the user interface components (with a lot 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 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());

... test completed successfully. Without sleep (), this is actually not suitable for race condition.

, , - Espresso, Idling. ...

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

... , Espresso , ... , , . , , 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
    }
}
+4
2

, , , , Espresso :

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

. ( ):

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

, , , . , :

  • :

    Runnable myRunnable = new Runnable{...};
    
  • Runnable:

    InstrumentationRegistry.getInstrumentation().waitForIdle(myRunnable);
    

, , . :

// 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 //
+3

, , , .

, :

fragment.object_set(object);

fragment.object_get()

. , . , InstrumentationRegistry , - InstrumentationRegistry.getInstrumentation(). RunOnMainSync (Runnable)

:

, , . , , , .

, , , :

Runnable r = () -> fragment.object_set(object);
InstrumentationRegistry.getInstrumentation().runOnMainSync(r);

//assertions
fragment.object_get()
+1

Source: https://habr.com/ru/post/1621040/


All Articles