Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JUnit Scheduler that doesn't depend on Android

I´m trying to use MVP to enhance unit testing and run tests faster (because I'm testing logic not android code so I avoid using things like RobotElectric).

But I´m using RXAndroid and it needs Looper to get Schedulers.io() and AndroidSchedulers.mainThread() and when I try to run sometime like

class Phone {
    public Observable<> sendSms(String number){
        //...
    }
}

Phone.getInstance().sendSms(phoneNumber)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(phone -> {
                    mView.dismissProgress();
                    mView.startCodeView(phone);
                }, error -> {
                    mView.dismissProgress();
                    mView.showError(error);
                });

I get:

Caused by: java.lang.RuntimeException: Method getMainLooper in android.os.Looper not mocked. See http://g.co/androidstudio/not-mocked for details.
at android.os.Looper.getMainLooper(Looper.java)
at rx.android.schedulers.AndroidSchedulers.<clinit>(AndroidSchedulers.java:27)
... 28 more

I tried:

android {
  // ...
  testOptions { 
    unitTests.returnDefaultValues = true
  }
}

But it will not work because I want to run full JUnit tests and not Roboelectric or Espresso stuff.

How can I accomplish it? is there any Scheduler that will not crash because of this?

like image 816
Daniel Gomez Rico Avatar asked Oct 10 '15 20:10

Daniel Gomez Rico


2 Answers

I am also using scheduler thread for this, but in my test SetUp and TearDown.

@Before
public void setUp() throws Exception {
    RxAndroidPlugins.getInstance().registerSchedulersHook(new RxAndroidSchedulersHook() {
        @Override
        public Scheduler getMainThreadScheduler() {
            return Schedulers.immediate();
        }
    });
}

@After
public void tearDown() {
    RxAndroidPlugins.getInstance().reset();
}

Will this help?

like image 113
Akhil Dad Avatar answered Oct 17 '22 07:10

Akhil Dad


I ended up adding using transformations and "flavour injection classes" for this, have a class that uses the main for prod/debug releases and use another class in the test flavour folder for testing Schedulers.immediate().

normal flavoured class:

public class Transformer {

  public static <T> Observable.Transformer<T, T> applyIoSchedulers() {
    return observable -> observable.subscribeOn(getIoScheduler())
        .observeOn(getMainScheduler());
  }

  private static Scheduler getIoScheduler() {
    return Schedulers.io();
  }

  private static Scheduler getMainScheduler() {
    return AndroidSchedulers.mainThread();
  }
}

Testing flavoured class:

public class Transformer {

  public static <T> Observable.Transformer<T, T> applyIoSchedulers() {
    return observable -> observable.subscribeOn(getIoScheduler())
        .observeOn(getMainScheduler());
  }

  private static Scheduler getIoScheduler() {
    return Schedulers.immediate() ;
  }

  private static Scheduler getMainScheduler() {
    return Schedulers.immediate() ;
  }
}

Then use it with transformations:

mSessionRepository.login(...)
        .compose(Transformer.applyIoSchedulers())
        .subscribe(session -> { })
like image 37
Daniel Gomez Rico Avatar answered Oct 17 '22 08:10

Daniel Gomez Rico