Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RxAndroid - java.lang.IllegalStateException: Another strategy was already registered

I am writing a unit test and need to mock an Observable (from retrofit)

The code in the tested component is as follows:

getApiRequestObservable()
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.io())
                .subscribe(...)

In the unit test (against the JVM so AndroidSchedulers are not available) I need to make it all synchronous so my tests will look like:

@Test
public void testSomething() {
    doReturn(mockedResponse).when(presenter).getApiRequestObservable();
    presenter.callApi();
    verify(object,times(1)).someMethod();
}

To do this, I should register hooks in a setUp() method:

@Before
    public void setUp() throws Exception {

        // AndroidSchedulers.mainThread() is not available here so we fake it with this hook
        RxAndroidPlugins.getInstance().registerSchedulersHook(new RxAndroidSchedulersHook() {
            @Override
            public Scheduler getMainThreadScheduler() {
                return Schedulers.immediate();
            }
        });

       // We want synchronous operations
        RxJavaPlugins.getInstance().registerSchedulersHook(new RxJavaSchedulersHook(){
            @Override
            public Scheduler getIOScheduler() {
                return Schedulers.immediate();
            }
        });
    }

But this throws the above exception as I am apparently not allowed to register two hooks. Is there any way around that?

like image 460
znat Avatar asked Sep 20 '16 20:09

znat


1 Answers

The problem is that you're not resetting test state - you can verify that by running single test. To fix your particular problem you need to reset rx plugins state like so:

@Before
public void setUp(){
    RxJavaPlugins.getInstance().reset();
    RxAndroidPlugins.getInstance().reset();
    //continue setup
    ...
}

You can even wrap the reset into a reusable @Rule as described by Alexis Mas blog post:

public class RxJavaResetRule implements TestRule {

    @Override
    public Statement apply(Statement base, Description description) {
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                //before: plugins reset, execution and schedulers hook defined

                RxJavaPlugins.getInstance().reset();
                RxAndroidPlugins.getInstance().reset();
                // register custom schedulers
                ...
                base.evaluate();
            }
        };
    }
}
like image 65
miensol Avatar answered Oct 29 '22 11:10

miensol