I have a function that I want to test which runs in an okHttp callback. I'm trying to test it using Robolectrics but the callback is never executed. I presume that is because the test moves on after request without waiting for okHttp to return. So far I've tried:
ShadowLooper.pauseMainLooper();
Robolectric.flushBackgroundScheduler();
ShadowLooper.unPauseMainLooper();
but that didn't work. Any suggestions?
EDIT:
Here's an example of my code:
ApiClient.sendSomeDataToServer(data, callback);
Where ApiClient is a helper class containing okHttp client. sendSomeDataToServer API call looks something like this:
public static void sendSomeDataToServer(MyObject data, Callback callback){
final Request request = new Request.Builder()
.url(API_SOME_URL)
.post(RequestBody.create(JSON, myObject.getAsJson().toString()))
.build();
sHttpClient.newCall(request).enqueue(callback);
}
Where sHttpClient is an initialised OkHttpClient.
I can test the execution of above by forcing Thread.sleep(5000)
inside my test code and providing custom callback. The code I'm trying to test is inside the callback. Any suggestions how I can test that? I really don't want to change the main code to fit the test framework - should be the other way round.
Lets assume you have next code. Interface:
@GET("/user/{id}/photo")
void listUsers(@Path("id") int id, Callback<Photo> cb);
Implementation:
public void fetchData() {
RestAdapter restAdapter = new RestAdapter.Builder()
.setServer("baseURL")
.build();
ClientInterface service = restAdapter.create(ClientInterface.class);
Callback<Photo> callback = new Callback<Photo>() {
@Override
public void success(Photo o, Response response) {
}
@Override
public void failure(RetrofitError retrofitError) {
}
};
service.listUsers(435, callback);
}
First of all you need to change service
instantiation to service
injection (as parameter or field). I will do it as parameter:
public void fetchData(ClientInterface clients) {
}
After this text is quite trivial:
@Test
public void checkThatServiceSuccessIsProcessed() {
ClientInterface mockedClients = mock(ClientInterface.class);
activity.fetchData(mockedClients);
// get callback
ArgumentCaptor<Callback<Photo>> captor = (ArgumentCaptor<Callback<Photo>>)ArgumentCaptor.forClass(Callback.class);
verify(mockedInterface).listUsers(anything(), captor.capture());
Callback<Photo> passedCallback = captor.value();
// run callback
callback.success(...);
// check your conditions
}
The used library for mocking and verifying is Mockito
.
There will be one warning with captor instantiation because of generics but it fixable if you will use @Captor
annotation instead of creating captor by hands.
The parameter injection is not perfect, especially for case of activities. This was used to simplify example. Consider for proper injection with library or without. I would encourage you to try Dagger
for injections
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With