Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

espresso custom TestRunner with RxJava2 - using Rx2Idler getting null pointer exception

I have successfully created a custom espresso test runner which looks like this:

public class PomeloTestRunner extends AndroidJUnitRunner {

    @Override
    public void onCreate(Bundle arguments) {
        RxJavaPlugins.setInitComputationSchedulerHandler(
                Rx2Idler.create("RxJava 2.x Computation Scheduler"));

        RxJavaPlugins.setInitIoSchedulerHandler(Rx2Idler.create("RxJava 2.x Computation Scheduler"));
        RxJavaPlugins.setInitNewThreadSchedulerHandler(Rx2Idler.create("RxJava 2.x Computation Scheduler"));
        RxJavaPlugins.setInitSingleSchedulerHandler(Rx2Idler.create("RxJava 2.x Computation Scheduler"));

        super.onCreate(arguments);
    }
}

my network layer of my application is written in rxjava2 so and I needed a way to link the espresso scheduling with rxjava so I chose to use Rx2Idler

but the problem I am getting is that when I run my tests I am getting the following error:

FATAL EXCEPTION: RxCachedThreadScheduler-1
                                                   Process: com.mobile.pomelo.labs, PID: 11611
                                                   java.lang.NullPointerException: Attempt to invoke interface method 'void android.support.test.espresso.IdlingResource$ResourceCallback.onTransitionToIdle()' on a null object reference
                                                       at com.squareup.rx2.idler.DelegatingIdlingResourceScheduler.stopWork(DelegatingIdlingResourceScheduler.java:96)
                                                       at com.squareup.rx2.idler.DelegatingIdlingResourceScheduler$ScheduledWork.run(DelegatingIdlingResourceScheduler.java:142)
                                                       at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:61)
                                                       at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:52)
                                                       at java.util.concurrent.FutureTask.run(FutureTask.java:237)
                                                       at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:269)
                                                       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
                                                       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
                                                       at java.lang.Thread.run(Thread.java:818)

here is my actual test if it's of any importance. the test fails but if I remove the scheduler overrides it works with the sleep:

    @RunWith(AndroidJUnit4.class)

public class AuthenticationActivityTest {

    @Before
    public void setUp() throws Exception {
        mIntentsTestRule.getActivity().sharedPrefRepo.clearAll();
    }


    @Rule
    public IntentsTestRule<AuthenticationActivity> mIntentsTestRule =
            new IntentsTestRule<AuthenticationActivity>(AuthenticationActivity.class) {
                @Override
                protected Intent getActivityIntent() {
                    Context targetContext = InstrumentationRegistry.getInstrumentation()
                            .getTargetContext();
                    Intent result = new Intent(targetContext, AuthenticationActivity.class);
                    Bundle b = new Bundle();
                    b.putSerializable("action", AuthenticationActivity.LoginActions.LOGIN);

                    result.putExtras(b);
                    return result;
                }
            };



    @Test
    public void signupWithFacebook() {

        final Intent resultData = new Intent();
        resultData.putExtra("com.facebook.LoginFragment:Result", LoginClientCreator.createResult());
        intending(hasComponent(FacebookActivity.class.getName()))
                .respondWith(new Instrumentation.ActivityResult(Activity.RESULT_OK, resultData));

        // click signup fb button
        onView(withId(R.id.fb_login_button))
                .perform(click());

        // check facebook intent was hit
        intended(hasComponent(FacebookActivity.class.getName()), times(1));

        try {
            Thread.sleep(14000); // i dont want this to sleep,  i would rather the espresso idle sync work with rxjava2
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        ViewInteraction appCompatTextView = onView(allOf(withText("COLLECTIONS"), isDisplayed()));
        appCompatTextView.perform(click());
    }
}

also take note that all my rxjava calls look like the following:

public void execute(@NonNull Observer UseCaseSubscriber){
                 this.buildUseCaseObservable()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(UseCaseSubscriber);
    }

update: i am wondering if its the firebase network calls which are not idle synced. these calls are not using rxjava so could they be not handled by Rx2Idler ?

like image 389
j2emanue Avatar asked Oct 30 '22 00:10

j2emanue


1 Answers

I tried various options like setup RxJava plugins in onCreate() of Test Runner class, or registering ResourceCallback on all resources.

But solution worked for me is just setting up RxJavaPlugins after super.onStart()

Please check code here:

public class AppTestRunner extends AndroidJUnitRunner {

    @Override
    public void onStart() {
        super.onStart();

        setupRxJavaPlugins();
    }

    private void setupRxJavaPlugins() {
        // rx-java 2
        RxJavaPlugins.setInitComputationSchedulerHandler(Rx2Idler.create("RxJava 2.x Computation Scheduler"));

        RxJavaPlugins.setInitIoSchedulerHandler(Rx2Idler.create("RxJava 2.x IO Scheduler"));

        RxJavaPlugins.setInitNewThreadSchedulerHandler(Rx2Idler.create("RxJava 2.x NewThread Scheduler"));

        RxJavaPlugins.setInitSingleSchedulerHandler(Rx2Idler.create("RxJava 2.x Single Scheduler"));

        // rx-java 1
        rx.plugins.RxJavaPlugins.getInstance().registerSchedulersHook(RxIdler.hooks());
    }
}
like image 78
Prakash Avatar answered Nov 09 '22 08:11

Prakash