Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to JUnit test IntentService

I'm new into Android testing, I want to test an IntentService and I'm currently extending ServiceTestCase.

I'm trying to use a ResultReceiver but the problem is that OnReceiveResult is never called within the test case. (I also tried creating the ResultReceiver with new Handler() as the argument insetad of null but with the same result.

what am I doing wrong? what is the proper way to test an IntentService ?

this is the service:

public class MyService extends IntentService {

public MyService() {
    super("MyService");
}

public MyService(String name) {
    super(name);
}

@Override
protected void onHandleIntent(Intent intent) {
    final int action = intent.getIntExtra("action", 0);
    final int request = intent.getIntExtra("request", 0);
    final ResultReceiver receiver = (ResultReceiver) intent.getExtras().get("receiver");

    if (receiver == null) {
        return;
    }

    if (action == 0 || request == 0) {
        receiver.send(0, null);

        return;
    }
}

}

and this is the test:

public void testHandleInvalidRequests() {
    ResultReceiver receiver = new ResultReceiver(null) {
        @Override
        protected void onReceiveResult(int resultCode, Bundle resultData) {
            fail();
        }   
    };

    Intent intent = new Intent(mContext, MyService.class);
    intent.putExtra("receiver", receiver);
    startService(intent);

}
like image 677
Gal Ben-Haim Avatar asked Aug 12 '12 15:08

Gal Ben-Haim


Video Answer


2 Answers

I successfully managed to test my IntentService and I will show you conceptually how I did it.

First, you extend the Android Service Testing class: ServiceTestCase<MyIntentService>. Then you basically start the IntentService as you did using startService(intent).

Since the service under test is an IntentService, it will do all work in a spawned worker thread. If you do not block your test thread then your test method will immediately do assertions that will obviously fail since the test work in the background has probably not finished yet. Eventually, the test method will return and your test will fail.

What you need to do is to block your test thread after startService. Do this using a ReentrantLock and a Condition calling await() on it.

The IntentService then executes onHandleIntent in the background. I suggest you extend your IntentService and override onHandleIntent, calling super.onHandleIntent() and after that, signal your test thread that the work has been done. Do this on the same lock and condition used for blocking the testing thread.

like image 196
Jörg Avatar answered Sep 28 '22 03:09

Jörg


I know this is old, but as I had the same kind of problem, I'll post here how I finally managed to run a test on an IntentService. As @Joerg said, it is a threading issue.

public class MyServiceTest extends ServiceTestCase<MyService> {
    public MyServiceTest() {
        super(MyService.class);
    }

    public void testOnHandleIntent() throws Exception {
        Looper.prepare();
        final CountDownLatch latch = new CountDownLatch(1);

        ResultReceiver receiver = new ResultReceiver(new Handler()) {
            @Override
            protected void onReceiveResult(int resultCode, Bundle resultData) {
                latch.countDown();

                assertEquals(resultCode, 0);
                assertNull(resultData);
                fail();

                Looper.myLooper().quit();
            }
        };

        Intent intent = new Intent(getSystemContext(), MyService.class);
        intent.putExtra("receiver", receiver);
        getSystemContext().startService(intent);

        Looper.loop();

        assertThat(latch.getCount(), is(0L));
    }
}

The Looper and Handler classes are necessary so that the callback has a thread to be called on. The latch is there only as an example of a lock and as a means to assert that the code passed by the callback before the end of the test method.

If the quit() method of the Looper is not called, the test hangs.

ServiceTestCase is deprecated on the latest versions of Android, but the replacement (ServiceTestRule) doesn't support IntentService ...

like image 43
ianribas Avatar answered Sep 28 '22 05:09

ianribas