Mohammad Elsayed
Mohammad Elsayed

Reputation: 2066

RxJava android mvp unit test NullPointerException

I am new to Unit Testing in mvp, I want to make a verrry basic test to the presenter, which is responsible for making login, I just want to assert on

view.onLoginSuccess();

Here is the PresenterCode:

public LoginPresenter(LoginViewContract loginView,
                      LoginModelContract loginModel,
                      CurrentUserLoginModelContract currentUserLoginModel,
                      CompositeDisposable subscriptions) {

    this.subscriptions = subscriptions;

    this.loginView = loginView;

    this.loginModel = loginModel;

    this.currentUserLoginModel = currentUserLoginModel;
}

@Override
public void loginPres(LoginRequest loginRequest) {
    loginModel.loginUser(loginRequest)
        .subscribeOn(Schedulers.computation())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new SingleObserver<LoginResponse>() {

            @Override
            public void onSubscribe(Disposable d) {
                subscriptions.add(d);
            }

            @Override
            public void onSuccess(LoginResponse loginResponse) {
            //  do something with the response
                loginView.loginSuccessMessage(token, true);
            }

            @Override
            public void onError(Throwable e) {
                loginView.loginFailedErrorMessage();
                Timber.e(e, "Error while trying to login");
            }
        });
}

Android here is the test code:

@RunWith(MockitoJUnitRunner.class)
public class LoginPresenterTest {

@Mock
LoginViewContract view;
@Mock
LoginModelContract model;
@Mock
CurrentUserLoginModelContract localModel;

LoginPresenter SUT;

@Before
public void setUp() throws Exception {
    compositeDisposable = new CompositeDisposable();
    SUT = new LoginPresenter(view, model, localModel, compositeDisposable);
}

@Test
public void name() {
    LoginResponse singleResponse = new LoginResponse();

    TestScheduler testScheduler = new TestScheduler();

    when(model.loginUser(any()))
            .thenReturn(Single.just(new LoginResponse()));

    SUT.loginPres(any());
}

It just gives me NullPointerException, I think that Knowing how to test the success will help me test everything else, I have read about the TestScheduler, I tried it but did not help, I think I am doing something wrong, thanks in advance.

Upvotes: 3

Views: 862

Answers (2)

Kingfisher Phuoc
Kingfisher Phuoc

Reputation: 8190

The problem is your TestScheduler. You should create a helper class to provide schedulers for your observable. Something likes:

class RxProvider{
     fun provideIOScheduler()
     fun provideAndroidMainScheduler()
}

//Then you can call the rxprovider inside your presenter:
loginModel.loginUser(loginRequest)
    .subscribeOn(rxProvider.provideIOScheduler())
    .observeOn(rxProvider.provideAndroidMainScheduler())
// inside your test cases
when(rxProvider....).thenReturn(testSchedulers)

P/s: 1 more tip, you should mock your LoginResponse instead of calling new everywhere.

Upvotes: 1

prfarlow
prfarlow

Reputation: 4361

You made a TestScheduler in your test class, but your Presenter doesn't know about it. Just like you have your view, model, localModel, and compositeDisposable as dependencies of the presenter, you need to add two new dependencies: Your IO Scheduler (Schedulers.computation() in the non test code, and new TestScheduler() in the test code) and your UI Scheduler (AndroidSchedulers.mainThread() in the non test code, and new TestScheduler() in the test code).

Once you do that, you can set up 2 new TestSchedulers in your test code. Declare them as testIoScheduler = new TestScheduler() and testUiScheduler = new TestScheduler(). Then, right after you call the method under test (SUT.loginPres(any());), you can invoke the schedulers with testIoScheduler.triggerActions() and testUiScheduler.triggerActions()

Upvotes: 1

Related Questions