asf
asf

Reputation: 355

Android testing with RxJava 2

I'm learning to write tests. I wrote my first test and got error from RxJava 2 + Retrofit.

java.lang.ExceptionInInitializerError on line .subscribeOn(Schedulers.io())

Code:

public void search(String query) {
    getViewState().showProgress();
    disposable.add(dataManager
            .searchMovies(query)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(
                    response -> {
                        getViewState().hideProgress();
                        if(response.isSuccessful()) {
                            getViewState().showSearchResults(response.body());
                        } else {
                            getViewState().showToast("Error " + response.code());
                        }
                    }, e -> {
                        getViewState().showToast(e.getMessage());
                        getViewState().hideProgress();
                    }
            ));
}

My test:

public class SearchPresenterTest {
    @Rule
    public TestComponentRule testComponentRule = new TestComponentRule();

    SearchPresenter searchPresenter;
    @Mock ISearchView$$State searchView$$State;
    @Mock DataManager dataManager;

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

        RxJavaPlugins.reset();
        RxJavaPlugins.setInitIoSchedulerHandler(schedulerCallable -> Schedulers.trampoline());

        RxAndroidPlugins.reset();
        RxAndroidPlugins.setInitMainThreadSchedulerHandler(schedulerCallable -> Schedulers.trampoline());

        RxJavaPlugins.setIoSchedulerHandler(scheduler -> Schedulers.trampoline());
        RxAndroidPlugins.setMainThreadSchedulerHandler(schedulerCallable -> Schedulers.trampoline());

        searchPresenter = new SearchPresenter();
        searchPresenter.setViewState(searchView$$State);
    }

    @Test
    public void searchTest() {
        MovieList movieList = new MovieList();
        Response response = Response.success(new MovieList());
        Observable<Response<MovieList>> obs = Observable.just(response);

        when(dataManager.searchMovies(anyString())).thenReturn(obs);
        searchPresenter.search(searchRequest());

        verify(searchView$$State).showProgress();
        verify(searchView$$State).hideProgress();
        verify(searchView$$State).showSearchResults(movieList);
    }

    private String searchRequest() {
        return "pirates";
    }
}

I tried to fix it with RxJavaPlugins.setIoSchedulerHandler() and other method in @Before but it doesn't help.

Upvotes: 1

Views: 1143

Answers (1)

asf
asf

Reputation: 355

This fixed my issue:

@BeforeClass
public static void setUpRxSchedulers() {
    Scheduler immediate = new Scheduler() {
        @Override
        public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) {
            // this prevents StackOverflowErrors when scheduling with a delay
            return super.scheduleDirect(run, 0, unit);
        }

        @Override
        public Worker createWorker() {
            return new ExecutorScheduler.ExecutorWorker(Runnable::run);
        }
    };

    RxJavaPlugins.setInitIoSchedulerHandler(scheduler -> immediate);
    RxJavaPlugins.setInitComputationSchedulerHandler(scheduler -> immediate);
    RxJavaPlugins.setInitNewThreadSchedulerHandler(scheduler -> immediate);
    RxJavaPlugins.setInitSingleSchedulerHandler(scheduler -> immediate);
    RxAndroidPlugins.setInitMainThreadSchedulerHandler(scheduler -> immediate);
}

Upvotes: 4

Related Questions