Mocking Bound Services on Android

Let’s suppose we have a Fragment that we want to unit test.
However, let’s also suppose that this fragment binds to/unbinds from a service through its lifecycle callback (onStart(), onStop()).

The main advantage of Bound Service  is that the latter lives only if at least one client is bound to it. By binding to/unbinding from a Service through a Fragment or Activity’s lifecycle, we are in full control of the existence of that Service and triggers it only when the user needs it.

To use a bound service, you mainly need 2 classes : an Android Service and a ServiceConnection that monitors the state of the service connection (Service connected/disconnected).

Below a very simple Service and ServiceConnection :

 

As you can see, as soon as the service is created, an expensive task is triggered within the onCreate() callback.

To bind to the service, we will make proper use of the ServiceConnector within our Fragment’s life cycle :

The Unit Test

As we have already seen, as soon as the service is created, an expensive task is triggered within the onCreate() callback. This could lead to pollute and add uncertainty to the result of our unit test (such as the IBinder being null within the onServiceConnected() callback). Just to remind you, a good unit test should be consistent, which means that it should always return the same result for the same test.

So in order not to be disrupted by the Service, we are goind to mock not only the Service, but also stub the IBinder. Thus, anytime a client (the fragment in our case) wants to bind to the Service, it will receive a stub IBinder that will return a mock Service.
Let’s have a look to the Unit Test (we will use Robolectric and Mockito to do so ) and specifically to the mockBoundLocalService() method:

The Robolectric’s ShadowApplication object has a method called setComponentNameAndServiceForBindService() that allows to set a IBinder for the given Service ComponentName. Using this setter, we are able to pass a stub IBinder within the onServiceConnected() callback whenever a client tries to bind to our service.