Android: get reference to started Service in instrumentation test

岁酱吖の 提交于 2019-12-04 13:37:01
MyDogTom

Replace your application with special version "for tests". Do it by providing custom instrumentation test runner. Mock your dependencies it this "app for tests". See for details

Here is a simplified example how "app for test" can be used. Let's assume you want to mock network layer (eg. Api) during tests.

public class App extends Application {
    public Api getApi() {
        return realApi;
    }
}

public class MySerice extends Service {
    private Api api;
    @Override public void onCreate() {
        super.onCreate();
        api = ((App) getApplication()).getApi();
    }
}

public class TestApp extends App {
    private Api mockApi;

    @Override public Api getApi() {
        return mockApi;
    }

    public void setMockApi(Api api) {
        mockApi = api;
    }
}

public class MyTest {
    @Rule public final ServiceTestRule mServiceTestRule = new ServiceTestRule();

    @Before public setUp() {
        myMockApi = ... // init mock Api
        ((TestApp)InstrumentationRegistry.getTargetContext()).setMockApi(myMockApi);
    }

    @Test public test() {
        //start service
        //use mockApi for assertions
    }
}

In the example dependency injection is done via application's method getApi. But you can use Dagger or any others approaches in the same way.

I found a very simple way for doing this. You can just perform a binding and you'll get the reference to the already running service, there are no conflicts with service creation because you already started it with onStartCommand, if you check you will see onCreate is called only once so you can be sure it is the same service. Just add the following after your sample:

    Intent serviceIntent =
            new Intent(InstrumentationRegistry.getTargetContext(),
                    NetworkMonitorService.class);

    // Bind the service and grab a reference to the binder.
    IBinder binder = mServiceRule.bindService(serviceIntent);

    // Get the reference to the service
    NetworkMonitorService service =
            ((NetworkMonitorService.LocalBinder) binder).getService();

    // Verify that the service is working correctly however you need
    assertThat(service, is(any(Object.class)));

I hope it helps.

this works at least for bound services:

@Test
public void testNetworkMonitorService() throws TimeoutException {

    Intent intent = new Intent(InstrumentationRegistry.getTargetContext(), NetworkMonitorService.class);
    mServiceRule.startService(intent);

    IBinder binder = mServiceRule.bindService(intent);
    NetworkMonitorService service = ((NetworkMonitorService.LocalBinder) binder).getService();

    mServiceRule.unbindService();
}

to access fields, annotate with @VisibleForTesting(otherwise = VisibleForTesting.NONE)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!