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);
}
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.
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
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With