Тестирование okHttp-запросов с помощью Robolectric – обратные вызовы

У меня есть функция, которую я хочу проверить, которая работает в обратном вызове okHttp. Я пытаюсь проверить его с помощью Robolectrics, но обратный вызов никогда не выполняется. Я предполагаю, что это потому, что тест движется по запросу, не дожидаясь okHttp для возврата. До сих пор я пробовал:

ShadowLooper.pauseMainLooper(); Robolectric.flushBackgroundScheduler(); ShadowLooper.unPauseMainLooper(); 

Но это не сработало. Какие-либо предложения?

РЕДАКТИРОВАТЬ:

Вот пример моего кода:

 ApiClient.sendSomeDataToServer(data, callback); 

Где ApiClient – это вспомогательный класс, содержащий okHttp-клиент. Вызов sendSomeDataToServer API выглядит примерно так:

 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); } 

Где sHttpClient – инициализированный OkHttpClient.

Я могу проверить выполнение выше, заставив Thread.sleep(5000) внутри моего тестового кода и предоставив пользовательский обратный вызов. Код, который я пытаюсь проверить, находится внутри обратного вызова. Любые предложения, как я могу это проверить? Я действительно не хочу менять основной код, чтобы он соответствовал тестовой структуре – должен быть наоборот.

Предположим, у вас есть следующий код. Интерфейс:

 @GET("/user/{id}/photo") void listUsers(@Path("id") int id, Callback<Photo> cb); 

Реализация:

 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); } 

Прежде всего вам нужно изменить экземпляр service инъекцию service (в качестве параметра или поля). Я сделаю это как параметр:

 public void fetchData(ClientInterface clients) { } 

После этого текст довольно тривиален:

 @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 } 

Используемая библиотека для издевательств и проверки – Mockito .

Будет одно предупреждение с созданием экземпляра из-за дженериков, но оно может быть @Captor если вы будете использовать аннотацию @Captor вместо создания захвата руками.

Инъекция параметров не идеальна, особенно для случая активности. Это было использовано для упрощения примера. Подумайте о правильной инъекции с библиотекой или без нее. Я бы посоветовал вам попробовать Dagger для инъекций

Вы можете использовать ArgumentCaptor (класс Mockito). Ссылка: http://www.mdswanson.com/blog/2013/12/16/reliable-android-http-testing-with-retrofit-and-mockito.html