nyarlathotep77
nyarlathotep77

Reputation: 181

Is it possible to run a Retrofit observable synchronously?

I'm trying to migrate my app to work with RxJava. I already use Retrofit and therefore I'm trying to use a Retrofit interface which methods return Observables. However I'm now having issues with coding tests against it, as I can't get the Observable to run on the main thread; I'm trying to use Scheduler.immediate() for it. It seems that Retrofit doesn't allow to override it's behaviour, which makes totally sense for the real execution flow, but it makes testing very difficult. As I've just started with RxJava + Retrofit I just hope I'm doing something wrong instead.

Below is what the code looks like:

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

where

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

and

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

Upvotes: 3

Views: 3070

Answers (1)

Praveer Gupta
Praveer Gupta

Reputation: 4010

If you modify your test to add testSubscriber.awaitTerminalEvent();, then your test will wait for the call to complete and hence the test will pass. You will still have to do an assertCompleted() as the terminal event can be either of successful completion or error.

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

I looked up the source code of Retrofit 1.9.0 and as per RxSupport class, the call is always executed in a separate thread provided by the httpExecutor. Hence using Schedulers.immediate() did not cause the call to happen in the main thread.

Upvotes: 5

Related Questions