Можно ли синхронно запускать наблюдаемую модификацию?

Я пытаюсь перенести свое приложение для работы с RxJava. Я уже использую Retrofit и поэтому пытаюсь использовать интерфейс Retrofit, методы которого возвращают Observables. Однако теперь у меня проблемы с тестами кодирования, так как я не могу заставить Observable работать в основном потоке; Я пытаюсь использовать для этого Scheduler.immediate(). Кажется, что Retrofit не позволяет переопределить его поведение, что имеет смысл для реального потока выполнения, но очень затрудняет тестирование. Поскольку я только начал с RxJava + Retrofit, я просто надеюсь, что вместо этого делаю что-то не так.

Ниже показано, как выглядит код:

@Test
public void shouldCompleteRequest() {
    SomeRestRequest request = new SomeRestRequest(arg1, arg2);
    TestSubscriber<SomeRestResponse> testSubscriber = new TestSubscriber<>();
    new SomeRestCommand(mRestApi,
            arg1, arg2
            Schedulers.immediate(),
            Schedulers.immediate(),
            mMockEventBus).execute(request, testSubscriber);
    testSubscriber.assertCompleted();
}

куда

public void execute(T request, Observer<S> observer) {
    getCommand(request)
        .observeOn(mObserveOnScheduler) //The test injects Schedulers.immediate()
        .subscribeOn(mSubscribeOnScheduler) //The test injects Schedulers.immediate()
        .subscribe(observer);
}

,

@Override
protected Observable<SomeRestResponse> getCommand(SomeRestRequest request) {
    return mRestApi.restCommand(arg1, arg2);
}

а также

public interface RestApi {
    @GET("/someEndPoint")
    Observable<SomeRestResponse> restCommand(@Query("arg1") String arg1, @Query("arg2") String arg2);
}

person nyarlathotep77    schedule 23.01.2016    source источник
comment
Модернизация не позволяет переопределить его поведение. Можете ли вы уточнить это подробнее? Трудно сказать, не видя кода.   -  person Aaron He    schedule 23.01.2016
comment
@AaronHe, кажется невозможным запустить Retrofit Observable в основном потоке, как я хотел бы сделать для своих тестов с помощью Scheduler.immediate().   -  person nyarlathotep77    schedule 23.01.2016


Ответы (1)


Если вы измените свой тест, чтобы добавить testSubscriber.awaitTerminalEvent();, тогда ваш тест будет ожидать завершения вызова и, следовательно, тест будет пройден. Вам все равно придется выполнить assertCompleted(), так как терминальным событием может быть либо успешное завершение, либо ошибка.

@Test
public void shouldCompleteRequest() {
    SomeRestRequest request = new SomeRestRequest(arg1, arg2);
    TestSubscriber<SomeRestResponse> testSubscriber = new TestSubscriber<>();
    new SomeRestCommand(mRestApi,
            arg1, arg2
            Schedulers.immediate(),
            Schedulers.immediate(),
            mMockEventBus).execute(request, testSubscriber);

    testSubscriber.awaitTerminalEvent(); // add this line here
    testSubscriber.assertCompleted();
}

Я просмотрел исходный код Retrofit 1.9.0, и в соответствии с классом RxSupport вызов всегда выполняется в отдельном потоке, предоставленном классом httpExecutor. Следовательно, использование Schedulers.immediate() не приводит к тому, что вызов происходит в основном потоке.

person Praveer Gupta    schedule 23.01.2016
comment
Спасибо за ваш подробный ответ. Это именно то, что я делаю, но мой тест завершается до фактического запроса REST. На самом деле я не вижу никаких журналов модернизации во время выполнения теста. - person nyarlathotep77; 23.01.2016
comment
Я действительно вижу журналы модернизации, и запрос выполняется правильно, но я все равно получаю: java.lang.AssertionError: Not completed! - person nyarlathotep77; 23.01.2016
comment
Это произошло бы, если бы вы использовали метод subscribeOn(scheduler) для наблюдаемого в методе, который вы пытаетесь протестировать. Это приводит к тому, что тест и модификация выполняются в разных потоках. У вас есть два варианта: во-первых, внедрить Scheduler, чтобы вы могли заменить Scheduler на Schedulers.immediate() в тесте. Если вы уже использовали что-то вроде subscribeOn(Schedulers.io()), то вам придется использовать второй способ использования RxJavaPlugins и RxJavaSchedulersHook. - person Praveer Gupta; 23.01.2016
comment
@praver09, спасибо. Я уже передаю планировщики через DI. В моей тестовой конфигурации как subscribeOn(), так иObservOn() получают Schedulers.immediate(). Я постараюсь поделиться кодом позже. - person nyarlathotep77; 23.01.2016
comment
@ nyarlathotep77 - я обновил свой ответ на основе предоставленной вами информации. Надеюсь, поможет. - person Praveer Gupta; 25.01.2016
comment
хороший звонок @praveer09. Прошлой ночью я просмотрел код Retrofit 1.9.0 и понял то же самое. Большое спасибо! Глядя на Retrofit 2.0.0, я подозреваю, что это поведение могло измениться, но мне нужно это проверить. - person nyarlathotep77; 25.01.2016