Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ActivityUnitTestCase and Activity#runOnUiThread

My test focuses on an AsyncTask completing and validating that a subsequent Activity is started.

It's known that AsyncTask#onPostExecute is not invoked unless the AsyncTask is instantiated and executed from the UI thread, so my (test visible) method to invoke the AsyncTask goes through the necessary precautions to ensure this behavior--via a Runnable that immediately runs if on the UI thread or is scheduled to run on the UI thread.

When this method is invoked from an ActivityUnitTestCase test, the Runnable that instantiates and executes this AsyncTask via Activity#runOnUiThread ends up running on a thread other than the UI thread. Is there a way to ensure that this Runnable will execute on the UI thread from within the Activity?

Addenda:

  • The test runs as hoped under a ActivityInstrumentationTestCase2 class, but I don't have access to ActivityUnitTestCase#getStartedActivityIntent. I am aware of Instrumentation.ActivityMonitor and it's a non-solution.
  • Runnables scheduled on ActivityUnitTestCase#runTestOnUiThread do run on the UI thread.
  • I'm not looking to redefine my test.
  • Oddly enough, ActivityUnitTestCase#startActivity calls Activity#onCreate NOT on the UI thread.

Edit: Here's a bit of (untested) code that demonstrates the essence of the problem:

// ExampleActivityTests.java

class ExampleActivityTests : public ActivityUnitTestCase <ExampleActivity> {

    public void testThatRequiresUiThread() {

        startActivity (new Intent(), null, null);
        // ...call instrumentation onStart, onResume...

        runTestOnUiThread(new Runnable() {
            public void run() {
                boolean isUiThread = Thread.currentThread() == Looper.getMainLooper().getThread();
                Log.d ("A", "Running on UI Thread? " + isUiThread);
            }
        });

        getActivity().methodRequiringUiThread();

        // assertions here...
    }
}

// ExampleActivity.java -- just the relevant method

    public void methodRequiringUiThread() {

        runOnUiThread(new Runnable() {
            public void run() {
                boolean isUiThread = Thread.currentThread() == Looper.getMainLooper().getThread();
                Log.d ("B", "Running on UI Thread? " + isUiThread);
            }
         });
    }

In LogCat we'll see:

A | Running on UI Thread? true
B | Running on UI Thread? false
like image 309
Travis Avatar asked Mar 14 '12 00:03

Travis


1 Answers

Calling ActivityUnitTestCase#startActivity on the UI thread solves my problem.

public void testThatRequiresUiThread() {

    runTestOnUiThread(new Runnable() {

        @Override
        public void run() {
            startActivity(new Intent(), null, null);
        }
    });

    // ...
    getActivity().methodRequiringUiThread();

    // rest of test...
}

yields

A | Running on UI Thread? true
B | Running on UI Thread? true
like image 83
Travis Avatar answered Oct 04 '22 01:10

Travis