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