#android #retrofit #mockwebserver
#Android #модернизация #макет веб-сервера
Вопрос:
Я хотел бы имитировать сетевое взаимодействие с помощью MockWebServer. К сожалению, модифицированные обратные вызовы никогда не вызываются. Мой код:
MockWebServer server = new MockWebServer();
server.enqueue(new MockResponse().setResponseCode(200).setBody("{}"));
server.play();
RestAdapter restAdapter = new RestAdapter.Builder().setConverter(new MyGsonConverter(new Gson()))
.setEndpoint(server.getUrl("/").toString()).build();
restAdapter.create(SearchService.class).getCount(StringUtils.EMPTY,
new Callback<CountContainer>() {
@Override
public void success(CountContainer countContainer, Response response) {
System.out.println("success");
}
@Override
public void failure(RetrofitError error) {
System.out.println("error");
}
});
server.shutdown();
Когда я использую модернизацию без обратных вызовов, это работает.
Комментарии:
1. Вам нужно прикрепить свой обратный вызов, ПРЕЖДЕ чем делать
server.play()
это?2. Когда я меняю порядок, это вызывает исключение java.lang. Исключение IllegalStateException: не удается получить порт перед вызовом play ()
Ответ №1:
Имея a Callback
, вы указываете Retrofit вызвать запрос и вызвать обратный вызов асинхронно. Это означает, что ваш тест завершается до того, как что-либо произойдет.
Есть два способа заставить это работать:
- Используйте блокировку в конце теста и подождите, пока не будет вызван один из методов обратного вызова.
- Передайте экземпляр синхронного
Executor
(тот, который просто вызывает.run()
немедленно) вsetExecutors
onRestAdapter.Builder
, чтобы фоновые вызовы и вызовы обратного вызова выполнялись синхронно.
Комментарии:
1. 1 спасибо, синхронная работа отлично работает.
executors
Разве блокировка не блокирует основной поток и, следовательно, не позволяет выполнять обратные вызовы (в основном потоке), и поэтому блокировка никогда не снимается? «Lock» я думаю о чем-то вродеCountDownLatch
2. Это не работает с retrofit 2. Как мне заставить его работать в модернизации 2?
Ответ №2:
Для модернизации 2 смотрите Ответ здесь: https://github.com/square/retrofit/issues/1259 Вы можете предоставить синхронного исполнителя OkHttpClient (через его диспетчера) и настроить этот клиент на модернизацию.Конструктор. Вы также можете установить тот же исполнитель для callbackExecutor.
Например:
CurrentThreadExecutor currentThreadExecutor = new CurrentThreadExecutor();
okhttp3.Dispatcher dispatcher = new okhttp3.Dispatcher(currentThreadExecutor);
OkHttpClient okHttpClient = new
OkHttpClient.Builder().dispatcher(dispatcher).build();
new Retrofit.Builder()
.client(okHttpClient)
.baseUrl(httpUrl)
.addConverterFactory(JacksonConverterFactory.create())
.callbackExecutor(currentThreadExecutor)
.build();
Пример реализации CurrentThreadExecutor:
https://gist.github.com/vladimir-bukhtoyarov/38d6b4b277d0a0cfb3af
Комментарии:
1. Это должно быть принято. Хороший материал.
Ответ №3:
В качестве альтернативы вы можете использовать Mockinizer с MockWebServer:
OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.mockinize(mocks) // <-- just add this line
.build()
И запросы / ответы, которые вы хотите имитировать, вы можете определить в mocks
значении. В вашем случае это будет выглядеть примерно так:
package com.appham.mockinizer.demo
import com.appham.mockinizer.RequestFilter
import okhttp3.mockwebserver.MockResponse
val mocks: Map<RequestFilter, MockResponse> = mapOf(
RequestFilter("/") to MockResponse().apply {
setResponseCode(200)
setBody("""{}""")
}
)