Android ServiceTestCase for IntentService

2020-02-25 11:52发布

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!

5条回答
对你真心纯属浪费
2楼-- · 2020-02-25 12:00

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.

查看更多
爷、活的狠高调
3楼-- · 2020-02-25 12:10

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.

查看更多
爷的心禁止访问
4楼-- · 2020-02-25 12:11

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

查看更多
倾城 Initia
5楼-- · 2020-02-25 12:20

This is my approach for now:

  1. 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
    }
    
  2. 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();
        }
    }
    
查看更多
一夜七次
6楼-- · 2020-02-25 12:22

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.

查看更多
登录 后发表回答