Unit testing retrofit RxJava

Unit testing retrofit RxJava

ReactiveX is a combination of the best ideas from the Observer pattern, the Iterator pattern, and functional programming.

RxAndroid is an extension to RxJava. It providers a scheduler to run code in the main thread of Android. It also provides the ability to create a scheduler that runs on a Android handler class. With this schedulers, you can define an observable which does its work in a background thread, and post our results to the main thread. This allows for example to replace a AsyncTask implementations which RxJava.

The subscriber observes in the main thread
Observable is called outside the main thread

To manage RxJava is not so difficult, When we have to use RxJava in Unit test, We need to create these element:

1. BaseSchedulerProvider (Father)
2. ImmediateSchedulerProvider (Testing)
3. SchedulerProvider (Application)

Android Test, Unit testing retrofit RxJava
You can check my complete example in GitHub

BaseSchedulerProvider :

public interface BaseSchedulerProvider {

    @NonNull
    Scheduler computation();

    @NonNull
    Scheduler io();

    @NonNull
    Scheduler ui();
}

ImmediateSchedulerProvider I use for a test:

public class ImmediateSchedulerProvider implements BaseSchedulerProvider {

    @NonNull
    @Override
    public Scheduler computation() {
        return Schedulers.immediate();
    }

    @NonNull
    @Override
    public Scheduler io() {
        return Schedulers.immediate();
    }

    @NonNull
    @Override
    public Scheduler ui() {
        return Schedulers.immediate();
    }
}

And SchedulerProvider I use in my Presenter

public class SchedulerProvider implements BaseSchedulerProvider {

    // Prevent direct instantiation.
    public SchedulerProvider() {
    }

    @Override
    @NonNull
    public Scheduler computation() {
        return Schedulers.computation();
    }

    @Override
    @NonNull
    public Scheduler io() {
        return Schedulers.io();
    }

    @Override
    @NonNull
    public Scheduler ui() {
        return AndroidSchedulers.mainThread();
    }
}

In my PresenterTest I setUp like this:

public class TopicPresenterTest {

            @Mock
            private RemoteDataSource mRemoteDataSource;

            @Mock
            private TopicContract.View mView;

            private BaseSchedulerProvider mSchedulerProvider;

            TopicPresenter mPresenter;

            List<Topics> mList;

            @Before
            public void setup() {
            MockitoAnnotations.initMocks(this);

                    Topics topics = new Topics(1, "Discern The Beach");
                    Topics topicsTwo = new Topics(2, "Discern The Football Player");
                    mList = new ArrayList<>();
                    mList.add(topics);
                    mList.add(topicsTwo);
//ADD IMMEDIATESCHEDULERPROVIDER !!!!!!!!!!!!!!!
                    mSchedulerProvider = new 
                    ImmediateSchedulerProvider();

                    mPresenter = new TopicPresenter(mRemoteDataSource, mView, mSchedulerProvider);

            }

            @Test
            public void fetchData() {

                when(mRemoteDataSource.getTopicsRx())
                        .thenReturn(rx.Observable.just(mList));

                mThemePresenter.fetch();

                InOrder inOrder = Mockito.inOrder(mView);
                inOrder.verify(mView).setLoadingIndicator(false);
                inOrder.verify(mView).showTopics(mList);

            }

}

And In my Presenter I call to my server with retrofit:

public class TopicPresenter {

    @NonNull
    private BaseSchedulerProvider mSchedulerProvider;

    public TopicPresenter(@NonNull RemoteDataSource remoteDataSource, @NonNull TopicContract.View view) {
                    this.mRemoteDataSource = checkNotNull(remoteDataSource, "remoteDataSource");
                    this.mView = checkNotNull(view, "view cannot be null!");
                    this.mSchedulerProvider = new SchedulerProvider();
 //ADD COMPOSITESUBSCRITPTION !!!!!!     
                    mSubscriptions = new CompositeSubscription();

                    mView.setPresenter(this);
    }

    @Override
    public void fetch() {

        Subscription subscription = mRemoteDataSource.getTopicsRx()
                .subscribeOn(mSchedulerProvider.computation())
                .observeOn(mSchedulerProvider.ui())
                .subscribe((List<Topics> listTopics) -> {
                            mView.setLoadingIndicator(false);
                            mView.showTopics(listTopics);
                        },
                        (Throwable error) -> {
                            try {
                                mView.showError();
                            } catch (Throwable t) {
                                throw new IllegalThreadStateException();
                            }

                        },
                        () -> {
                        });

        mSubscriptions.add(subscription);
    }

    @Override
    public void subscribe() {
        fetch();
    }

    @Override
    public void unSubscribe() {
        mSubscriptions.clear();
    }


}

You can check my complete example in GitHub

how to test the server call with Mockito, Retrofit and RxJava

how to test the server call with Mockito, Retrofit and RxJava

In this example you can learn how to test server call with Mockito and RxJava, We need this elements:

1. Service
2. RemoteDataSource
3. RemoteDataSourceTest

how to test the server call with Mockito, Retrofit and RxJava

Simple Service:

public interface Service {
    String URL_BASE = "https://guessthebeach.herokuapp.com/api/";

    @GET("topics/")
    Observable<List<Topics>> getTopicsRx();

}

For RemoteDataSource

public class RemoteDataSource implements Service {

    private Service api;

    public RemoteDataSource(Retrofit retrofit) {


        this.api = retrofit.create(Service.class);
    }


    @Override
    public Observable<List<Topics>> getTopicsRx() {
        return api.getTopicsRx();
    }
}

The key is MockWebServer from okhttp3.

This library makes it easy to test that your app Does The Right Thing when it makes HTTP and HTTPS calls. It lets you specify which responses to return and then verify that requests were made as expected.

Because it exercises your full HTTP stack, you can be confident that you’re testing everything. You can even copy & paste HTTP responses from your real web server to create representative test cases. Or test that your code survives in awkward-to-reproduce situations like 500 errors or slow-loading responses.

Use MockWebServer the same way that you use mocking frameworks like Mockito:

  1. Script the mocks.
  2. Run application code.
  3. Verify that the expected requests were made.

Here’s a complete example in RemoteDataSourceTest:

 
public class RemoteDataSourceTest {

    List<Topics> mResultList;
    MockWebServer mMockWebServer;
    TestSubscriber<List<Topics>> mSubscriber;

    @Before
    public void setUp() {
        Topics topics = new Topics(1, "Discern The Beach");
        Topics topicsTwo = new Topics(2, "Discern The Football Player");
        mResultList = new ArrayList();
        mResultList.add(topics);
        mResultList.add(topicsTwo);

        mMockWebServer = new MockWebServer();
        mSubscriber = new TestSubscriber<>();
    }

    @Test
    public void serverCallWithError() {
        //Given
        String url = "dfdf/";
        mMockWebServer.enqueue(new MockResponse().setBody(new Gson().toJson(mResultList)));
        Retrofit retrofit = new Retrofit.Builder()
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl(mMockWebServer.url(url))
                .build();
        RemoteDataSource remoteDataSource = new RemoteDataSource(retrofit);

        //When
        remoteDataSource.getTopicsRx().subscribe(mSubscriber);

        //Then
        mSubscriber.assertNoErrors();
        mSubscriber.assertCompleted();
    }

    @Test
    public void severCallWithSuccessful() {
        //Given
        String url = "https://guessthebeach.herokuapp.com/api/";
        mMockWebServer.enqueue(new MockResponse().setBody(new Gson().toJson(mResultList)));
        Retrofit retrofit = new Retrofit.Builder()
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl(mMockWebServer.url(url))
                .build();
        RemoteDataSource remoteDataSource = new RemoteDataSource(retrofit);

        //When
        remoteDataSource.getTopicsRx().subscribe(mSubscriber);

        //Then
        mSubscriber.assertNoErrors();
        mSubscriber.assertCompleted();
    }

}

You can check my example in GitHub

Learn RxJava

Learn RxJava

In this example you can understand different elements of RxJava with Strings.

Simple
This method creates an Observable such that when an Observer subscribes, the onNext() of the Observer is immediately called with the argument provided to Observable.just(). The onCompleted() will then be called since the Observable has no other values to emit.

Observable.create(subcriber ->{
        subcriber.onNext("Hello");
        subcriber.onNext("Javier Gonzalez");
        subcriber.onCompleated();
    });

Now with Exception:

    Observable.create(subcriber ->{
        subcriber.onNext("Hello");
        subcriber.onNext("Javier Gonzalez");
        subcriber.onError(new Exception("iOS user now allowed"));
    });

And there are another different ways to do:

    Observable.just("Hello again...");

    Observable.from(Arrays.asList("Hello", "again..."));

    Observable.from(new String[]{"Hello", "again..."});

    Observable.concat(Observable.just("Hello"), Observable.just("again..."));

    Observable.merge(Observable.just("Hello", "again..."), Observable.never());

Also you can check this example
And this post

RxJava retrolambda

RxJava retrolambda

This is a example how to use RxJava and Retrolambda on Android.
You can see the complete example in GitHub

Web Launcher

Java 8 introduced Lambdas Expressions, unfortunately Android does not support Java 8, so we are not able to take advantage of this with RxJava. Luckily there is a library called Retrolambda which backports lambdas to previous versions of Java. There is also a gradle plugin for Retrolambda that will allow the use of lambdas in an Android application.

In RxJava there are different elements:

1.BASIC(Observable)

2.ASYNCHRONOUS

3.SINGLES

4.SUBJECTS

5.MAP

6.DEBOUNCES

Basic

This method creates an Observable such that when an Observer subscribes, the onNext() of the Observer is immediately called with the argument provided to Observable.just(). The onCompleted() will then be called since the Observable has no other values to emit:

    Observable<List<String>> listObservable = Observable.just(getColorList());

    listObservable.subscribe(new Observer<List<String>>() { 

            @Override 
            public void onCompleted() { } 

            @Override 
            public void onError(Throwable e) { } 

            @Override
            public void onNext(List<String> colors) {
                mSimpleStringAdapter.setStrings(colors);
            }
    });

with lambda:

    Observable<List<String>> listObservable = Observable.just(getColorList());

    listObservable.subscribe(
                (List<String> colors)-> mSimpleStringAdapter.setStrings(colors),
                (error) -> {},
                () -> {});

Asynchronous

If we use it with Observable.just(), mRestClient.getFavoriteTvShows() will be evaluated immediately and block the UI thread. Enter the Observable.fromCallable() method. It gives us two important things: * The code for creating the emitted value is not run until someone subscribes to the Observer. * The creation code can be run on a different thread.

    Observable<List<String>> tvShowObservable = Observable.fromCallable(new Callable<List<String>>() { 

        @Override 
        public List<String> call() { 
            return mRestClient.getFavoriteTvShows(); 
        }
    });

    mTvShowSubscription = tvShowObservable
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                        new Observer<List<String>>() {
                            @Override
                            public void onCompleted() {

                            }

                            @Override
                            public void onError(Throwable e) {

                            }

                            @Override
                            public void onNext(List<String> tvShows) {
                                displayTvShows(tvShows);
                            }
                        });

with lambda:

    Observable<List<String>> tvShowObservable = Observable.fromCallable(() -> mRestClient.getFavoriteTvShows());
    mTvShowSubscription = tvShowObservable
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                (List<String> tvShows) -> displayTvShows(tvShows),
                (error) -> {},
                () -> {});

Singles

There’s a simpler version of an Observable called a Single. Singles work almost exactly the same as Observables. But instead of there being an onCompleted(), onNext(), and onError(), there are only two callbacks: * onSuccess() and onError().

    Single<List<String>> tvShowSingle = Single.fromCallable(new Callable<List<String>>() { 

        @Override
        public List<String> call() throws Exception {
            mRestClient.getFavoriteTvShows(); 
        }
    });

    mTvShowSubscription = tvShowSingle
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new SingleSubscriber<List<String>>() {
                    @Override
                    public void onSuccess(List<String> tvShows) {
                        displayTvShows(tvShows);
                    }

                    @Override
                    public void onError(Throwable error) {
                        displayErrorMessage();
                    }
                }); 

with lambda:

    Single<List<String>> tvShowSingle = Single.fromCallable(() -> mRestClient.getFavoriteTvShows());

    mTvShowSubscription = tvShowSingle
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe((List<String> tvShows) -> displayTvShows(tvShows),
                    (Throwable error) ->  displayErrorMessage());

Subjects

Subjects are special objects that are both an Observable and an Observer. With a PublishSubject, as soon as you put something in one end of the pipe it immediately comes out the other.

    PublishSubject<Integer> mCounterEmitter = PublishSubject.create();
    mCounterEmitter.subscribe(new Observer<Integer>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(Integer integer) {
                mCounterDisplay.setText(String.valueOf(integer));
            }
        });

with lambda:

    PublishSubject<Integer>  mCounterEmitter = PublishSubject.create();
    mCounterEmitter.subscribe(
                (Integer integer) ->  mCounterDisplay.setText(String.valueOf(integer)),
                (Throwable e) ->{},
                () -> { });

It increments a variable called mCounter. It calls onNext() on the mCounterEmitter with the new value of mCounter.

    mCounter ++;
    mCounterEmitter.onNext(mCounter);

Map

It’s a function that takes in one value and outputs another value. Usually there is some relationship between value put in to the map and the value that is output.

    Single.just(4).map(new Func1<Integer, String>() { 

        @Override 
        public String call(Integer integer) { 
            return String.valueOf(integer);
        } 
    }).subscribe(new SingleSubscriber<String>() { 

        @Override 
        public void onSuccess(String value) { 
            mValueDisplay.setText(value); 
        } 

        @Override 
        public void onError(Throwable error) { } 
        });

with lambda:

    Single.just(4).map((Integer integer) -> String.valueOf(integer))

                .subscribe((String value) -> mValueDisplay.setText(value),
                        (Throwable error) -> {});

Debounce

Everything together and a new concept: debounce. Let’s dive in. If you want to setup a PublishSubject such that it receives values the user types into a search box, fetches a list of suggestions based on that query, and then displays them.

    mSearchResultsSubject = PublishSubject.create();
    mTextWatchSubscription = mSearchResultsSubject
        .debounce(400, TimeUnit.MILLISECONDS)
        .observeOn(Schedulers.io())
        .map(new Func1<String, List<String>>() {

            @Override 
            public List<String> call(String s) { 
                return mRestClient.searchForCity(s); 
            } 
        })
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Observer<List<String>>() { 

            @Override 
            public void onCompleted() { }

            @Override 
            public void onError(Throwable e) { } 

            @Override
            public void onNext(List<String> cities) {
                handleSearchResults(cities); 
            }
        });
    });

with lambda:

    mSearchResultsSubject = PublishSubject.create();
    mTextWatchSubscription = mSearchResultsSubject
                .debounce(400, TimeUnit.MILLISECONDS)
                .observeOn(Schedulers.io())
                .map( (String string) -> mRestClient.searchForCity(string))
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe((List<String> cities) -> handleSearchResults(cities),
                        (Throwable e) -> {},
                        () -> {});

Libraries

The project is setup using:

You can see the complete example in GitHub

As the above only gives a rough overview of rxjava example I’d strongly recommend checking out the following: