androidunit-testingserviceandroid-asynctaskservicetestcase

AsyncTask.onPostExecute() never gets called in ServiceTestCase


I am writing a unit test for a service using ServiceTestCase.

The service basically executes an AsyncTask that does some work and then does something else in onPostExecute().

The service works as expected when I run and debug it in a (virtual) device.

But in the test extending ServiceTestCase, I only get into doInBackground(). Once the methods returns, onPostExecute() never gets called. I am letting the test sleep() so the AsyncTask has time to complete its work.

This is the simplified service:

public class ServiceToTest extends Service {
    private AtomicBoolean busy = new AtomicBoolean(false);

    @Override
    public IBinder onBind(final Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(final Intent intent, final int flags,
        final int startId) {
        this.handleCommand();
        return START_NOT_STICKY;
    }

    /**
    * Workaround for http://code.google.com/p/android/issues/detail?id=12117
    */
    @Override
    public void onStart(final Intent intent, final int startId) {
        this.handleCommand();
    }

    public void handleCommand() {
        new TaskToTest().execute();
    }

    public boolean isBusy() {
        return busy.get();
    }

    private class TaskToTest extends AsyncTask<Boolean, Void, TestInfo> {
        @Override
        protected void onPreExecute() {
            busy.set(true);
        }

        @Override
        protected TestInfo doInBackground(final Boolean... args) {
            return null;
        }

        @Override
        protected void onPostExecute(final TestInfo info) {
            busy.set(false);
        }
    }
}

An this is the test for it:

public class ServiceTest extends ServiceTestCase<ServiceToTest> {
    public ServiceTest() {
        super(ServiceToTest.class);
    }

    public void testIsBusy() throws InterruptedException {
        startService(new Intent("this.is.the.ServiceToTest"));  
        ServiceToTest serviceToTest = this.getService();
        assertTrue(serviceToTest.isBusy());
        Thread.sleep(10000);
        assertFalse(serviceToTest.isBusy());
    }
}

I suppose that the environment provided by ServiceTestCase is somewhat limited so this doesn't work, but is there anything I can do to make it work anyway?

Cheers, Torsten


Solution

  • The problem is that your background thread is waiting for the UI to be "alive", you need to call Looper.prepare() and Looper.loop(). It's better explained in this page.