Java – Handler.handleMessage is not called in the test, but is called in the application

Handler.handleMessage is not called in the test, but is called in the application… here is a solution to the problem.

Handler.handleMessage is not called in the test, but is called in the application

I have a service running in a separate process. The service spawns a new thread in the onCreate() method. This thread sends the message back to the service.

If I start the application manually, everything works fine – messages are received by the handler in my service. But in my tests, the handleMessage() method was never called.

How do I fix my test to make the handleMessage() method work?

Thanks!

Services:

public class MyService extends Service {

private ServiceHandler mHandler;
    private final int MSG_HELLO_WORLD = 1;

private final String TAG = getClass().getSimpleName();

@Override
    public IBinder onBind(Intent intent) {
         TODO: Return the communication channel to the service.
        return null;
    }

@Override
    public void onCreate() {
        Log.d(TAG, "MyService.onCreate");
        super.onCreate();

mHandler = new ServiceHandler();

new Thread(new Runnable() {
            @Override
            public void run() {
                Log.d(TAG, "Thread: run()");

while (true) {

try {
                        Log.d(TAG, "sleeping...");
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        Log.d(TAG, "Thread was interrupted.");
                        break;
                    }

Log.d(TAG, "sending message...");
                    Message msg = Message.obtain(mHandler, MSG_HELLO_WORLD);
                    msg.sendToTarget();
                }
            }
        }).start();

}

@Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "MyService.onStartCommand");
        return START_REDELIVER_INTENT;
    }

private class ServiceHandler extends Handler {

@Override
        public void handleMessage(Message msg) {
            Log.d(TAG, "ServiceHandler.handleMessage");

if (msg.what == MSG_HELLO_WORLD) {
                Log.d(TAG, "Hello World message received!");
            }
        }
    }

}

Test:

public class MyServiceTest extends ServiceTestCase<MyService> {

private static final String TAG = MyService.class.getSimpleName();

public MyServiceTest() {
        super(MyService.class);
    }

public void setUp() throws Exception {
        super.setUp();
    }

public void testStartService() throws Exception {

Intent startServiceIntent = new Intent(getContext(), MyService.class);

startService(startServiceIntent);

MyService myService = getService();

assertNotNull(myService);

 give the service some time to send messages
        Thread.sleep(10000);
    }
}

The app’s logcat output (handleMessage() is called):

MyService.onCreate
MyService.onStartCommand
Thread: run()
sleeping...
sending message...
sleeping...
ServiceHandler.handleMessage
Hello World message received!
sending message...
sleeping...

Logcat output of the test (handleMessage() not called):

MyService.onCreate
MyService.onStartCommand
Thread: run()
sleeping...
sending message...
sleeping...
sending message...
sleeping...
sending message...
sleeping...

Solution

I

thought your question was interesting, so I started digging.

If I start the app manually everything works fine – messages are received by the Handler in my service.

When you initialize mHandler with mHandler = new ServiceHandler() in the onCreate() method of MyService>, handler is associated with the message queue of the currently executing thread. The mHandler process Messages are sent from the queue which Looper handles >is looping Hello World News!”.

But in my test handleMessage() method is never get called.

When you test a service, its methods are called on the InstrumentationThread (see Threads in the Debugger), whose Looper is prepared but not cyclical, As a result, messages cannot be processed and do not appear in the log.

How can I fix my test to make handleMessage() method work?

I suggest the following options:

  • Bind MyServiceTest (bind) to the thread that calls the MyService method. Write another unit test for the component, and then merge that test with MyServiceTest into a common .java test file. This displays the desired logcat output.
  • Loop the InstrumentationThread prepared Looper in MyServiceTest. You can do this by adding Looper.loop() to the testStartService() method of MyServiceTest:

    public void testStartService() throws Exception {
    
    Intent startServiceIntent = new Intent(getContext(), MyService.class);
        startService(startServiceIntent);
        MyService myService = getService();
        assertNotNull(myService);
    
     Run the Looper (this call is to be added)
        Looper.loop();
    
    Thread.sleep(10000);
    }
    

    Note: Running Looper will display the desired logcat output, but the test will not stop because of Looper. loop() runs indefinitely until you call Looper.quit(). .

Related Problems and Solutions