I'm currently writing unit tests for an android application and stumbled into the following issue:
I use the ServiceTestCase
to test an IntentService
like this:
@Override
public void setUp() throws Exception {
super.setUp();
}
public void testService()
{
Intent intent = new Intent(getSystemContext(), MyIntentService.class);
super.startService(intent);
assertNotNull(getService());
}
However I noticed that my IntentService
is created (means that onCreate
is called) but I never receive a call into onHandleIntent(Intent intent)
Has anyone already tested an IntentService
with the ServiceTestCase
class?
Thanks!
I just got started into testing my own IntentService
and it's proving to be a bit of a headache.
Still trying to work things out but for the scenario where it seems that you do not receive a call to your method onHandleIntent()
, (I'm not very good with the technicalities behind junit
so forgive my use of terminology) it should be because the test framework, based on your code, actually tears down or end the test method once your call to startService
returns. There is insufficient time for onHandleIntent
to be triggered.
I verified the above theory by adding an infinite loop within my test case - only then can I see my log statements in onHandleIntent
logged.
This is a bit late, but I just struggled with this. You could solve this by creating a class that simply overrides the onStart of you service so it calls onHandleIntent
directly. So for instance, if you have a LocationUpdaterService, you could create a fake class that overrides the onStart
function like this:
public class LocationUpdaterServiceFake extends LocationUpdaterService {
@Override
public void onStart(Intent intent, int startId) {
onHandleIntent(intent);
stopSelf(startId);
}
LocationUpdaterService
is a subclass of IntentService, so when you write your tests, just use the LocationUpdaterServiceFake
class like this
public class LocationUpdateServiceTest extends ServiceTestCase<LocationUpdaterServiceFake> {
public LocationUpdateServiceTest()
{
super(LocationUpdaterServiceFake.class);
}
public void testNewAreaNullLocation()
{
Intent intent = new Intent();
intent.setAction(LocationUpdaterService.ACTION_NEW_AREA);
startService(intent);
}
}
Now whenever you call startService
, it will bypass the threading code in IntentService and just call your onHandleIntent
function
You just have to add a:
Thread.sleep(XXXXXXX);
Choose the XXXX
after the startService, then it will let the thread go into the onHandleIntent
method.
In Android Studio 1.1, when running tests using the Run/Debug Configuration | Android Tests facility on any unit under test code (UUT) that extends IntentService, the ServiceTestCase.java (JUnit?) code does not call onHandleIntent(Intent intent) method in the UUT. ServiceTestCase only calls onCreate so the problem is in the test code.
protected void startService(Intent intent) {
if (!mServiceAttached) {
setupService();
}
assertNotNull(mService);
if (!mServiceCreated) {
mService.onCreate();
mServiceCreated = true;
}
mService.onStartCommand(intent, 0, mServiceId);
mServiceStarted = true;
}
In my file smSimulatorTest.java:
public class smSimulatorTest extends ServiceTestCase<smSimulator>
At this point, I'm looking for other solutions in the testing framework that test UUTs through Intents since this is how IntentService is instantiated.
http://developer.android.com/reference/android/app/IntentService.html - To use it, extend IntentService and implement onHandleIntent(Intent). IntentService will receive the Intents, launch a worker thread, and stop the service as appropriate.
I, like others, put my code in the onHandleintent() as directed by the above documentation, however, ServiceTestCase only tests onStart and onStartCommand has shown above.
This is my approach for now:
The start Intent that invokes the service specifies the Service method to test
public void test_can_do_the_work() {
Intent startIntent = new Intent();
startIntent.putExtra("IN_TEST_MODE", "TEST_SPECIFIC_METHOD");
startIntent.setClass(getContext(), MyServiceToTest.class);
startService(startIntent);
assertNotNull(getService()); // Your assertion Service specific assertion
}
In the service onStart, we check for the specific Extra passed and call the method to test. This won't execute when Handle intent fired.
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
String in_test_mode = intent.getStringExtra("TEST_SPECIFIC_METHOD");
if(in_test_mode != null){
doServiceWork();
}
}