Единичный тест Retrofit и RxJava никогда не заканчивается, если возникает HttpException

78
11

Я пытаюсь выполнить единичный тест (JUnit), который проверяет Retrofit Observable в случае, когда веб-сервер возвращает 422 Unprocessable entity.

У меня есть следующая служба API (которую я создаю с помощью функции retrofit.create(AccountService.class)):

public interface AccountService {
@POST("users")
Observable<User> createNewUser(@Body User user, @Query("v_uuid") String vUuid, @Query("v_code") String vCode);
}

И я вызываю эту услугу из модульного теста:

Observable<User> observable = accountService
.createNewUser(newUser, "uuid", "code")
.subscribeOn(Schedulers.io());

Кроме того, я использую TestSubscriber<User>, чтобы заявить о моем наблюдении:

TestSubscriber<User> testSubscriber = new TestSubscriber<>(); 

observable
.observeOn(AndroidSchedulers.mainThread())
.subscribe(testSubscriber);

testSubscriber.awaitTerminalEvent();
// assert testSubscriber.getOnErrorEvents()

Я использую SchedulersHook (через JUnit @Rule), как описано в следующем сообщении в блоге: http://alexismas.com/blog/2015/05/20/unit-testing-rxjava/. Я использую Schedulers.immediate() в качестве замены для следующих планировщиков:

    Schedulers.io() Schedulers.computation() Schedulers.newThread() AndroidSchedulers.mainThread()

Но похоже, что тест никогда не закончится. Он зависает, когда я вызываю observable.observeOn(AndroidSchedulers.mainThread()).subscribe(testSubscriber); , В то же время этот код работает хорошо, если веб-сервер отвечает на 2xx codes. Также, если я удалю свой пользовательский SchedulersHook из кода, он станет работать, даже если сервер отвечает на 4xx codes.

Дополнительная информация: Я использую MockWebServer для эмуляции веб-сервера, и я вижу из журналов, что Retrofit отправляет запрос на сервер. Мои зависимости Gradle выглядят следующим образом:

testCompile 'junit:junit:4.12'
testCompile 'org.robolectric:robolectric:3.1-SNAPSHOT'
testCompile 'com.squareup.okhttp3:mockwebserver:3.1.2'

compile 'io.reactivex:rxjava:1.1.0'
compile 'io.reactivex:rxandroid:1.1.0'
compile 'com.squareup.okhttp3:okhttp:3.1.2'
compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'

ОБНОВЛЕНИЕ: после того, как вы выкапываете rxjava я обнаружил, что использование оператора merge и разных Schedulers (в частности, замена их с помощью SchedulersHook) приводит к бесконечным sleeps() где-то внутри OperatorMerge.InnerSubscriber<T>.

спросил(а) 2021-01-25T15:43:22+03:00 5 месяцев назад
1
Решение
63

Я, наконец, понял, что код причины никогда не заканчивается. Благодаря Dávid Karnok из сообщества (https://groups.google.com/forum/#!topic/rxjava/2rOHj1mvShk):

Что происходит, так это то, что поток очистки RxRingBuffer засыпает ближайшего планировщика, что предотвращает прогресс других компонентов.

Существует фундаментальная проблема с непосредственным планировщиком; это не настоящий планировщик и из-за его спящего характера, это может вызвать неожиданные зависания.

Для операторов тестирования гораздо лучше использовать TestScheduler напрямую и избегать использования RxJavaPlugins как можно больше.

После того, как я переключился на TestScheduler все началось, как и ожидалось.

Он также рекомендовал использовать инъекцию зависимостей (Dagger 2) для управления Schedulers.

ответил(а) 2021-01-25T15:43:22+03:00 5 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема