使用RxJava执行单元测试时获取NullPointerException

时间:2019-08-09 01:51:47

标签: android unit-testing mockito rx-java2 android-testing

我有登录演示者类,并且想要对其进行单元测试。

这就是登录演示者类的样子:

public class LoginPresenter<V extends LoginMvpView> extends BasePresenter<V>
        implements LoginMvpPresenter<V> {


    @Inject
    public LoginPresenter(DataManager dataManager,
                          SchedulerProvider schedulerProvider,
                          CompositeDisposable compositeDisposable) {
        super(dataManager, schedulerProvider, compositeDisposable);
    }

    @Override
    public void onAttach(V mvpView) {
        super.onAttach(mvpView);       
    }

    @Override
    public void login(String email, String password) {
        getMvpView().hideKeyboard();

        LoginRequest request = new LoginRequest();
        request.setEmail(email);
        request.setPassword(password);

        if(email == null || email.length() == 0){
            getMvpView().onError(R.string.msg_pls_fill_email);
            return;
        }    

        if(password == null || password.length() == 0){
            getMvpView().onError(R.string.msg_pls_fill_password);
            return;
        }

        getMvpView().showLoading();

        getCompositeDisposable().add(getDataManager()
                .login(request)
                .subscribeOn(getSchedulerProvider().io())
                .observeOn(getSchedulerProvider().ui())
                .subscribe(response -> {

                    if (!isViewAttached()) {
                        return;
                    }

                    getMvpView().openMainActivity();

                }, throwable -> {
                    if (!isViewAttached()) {
                        return;
                    }

                    getMvpView().hideLoading();

                    getMvpView().onError(R.string.api_default_error);

                })
        );
    }


}

这是测试类:

@RunWith(MockitoJUnitRunner.class)
public class LoginPresenterTest {

    @Mock
    LoginMvpView mMockLoginMvpView;
    @Mock
    DataManager mMockDataManager;

    private LoginPresenter<LoginMvpView> mLoginPresenter;

    private TestScheduler mTestScheduler;

    @BeforeClass
    public static void onlyOnce() throws Exception {
    }

    @Before
    public void setUp() throws Exception {
        CompositeDisposable compositeDisposable = new CompositeDisposable();
        mTestScheduler = new TestScheduler();
        TestSchedulerProvider testSchedulerProvider = new TestSchedulerProvider(mTestScheduler);
        mLoginPresenter = new LoginPresenter<>(
            mMockDataManager,
            testSchedulerProvider,
            compositeDisposable);
        mLoginPresenter.onAttach(mMockLoginMvpView);
    }

    @Test
    public void testServerLoginSuccess() {

        String email = "dummy@gmail.com";
        String password = "password";

        LoginResponse loginResponse = new LoginResponse();

        doReturn(Single.just(loginResponse))
                .when(mMockDataManager)
                .login(new LoginRequest(email, password));

        mLoginPresenter.login(email, password);

        mTestScheduler.triggerActions();

        verify(mMockLoginMvpView).showLoading();
        verify(mMockLoginMvpView).hideLoading();
        verify(mMockLoginMvpView).openMainActivity();
    }


    @After
    public void tearDown() throws Exception {
        mLoginPresenter.onDetach();
    }

}

这是调度程序提供程序类:

public class TestSchedulerProvider implements SchedulerProvider {

    private final Scheduler mTestScheduler;

    public TestSchedulerProvider(Scheduler testScheduler) {
        this.mTestScheduler = testScheduler;
    }

    @Override
    public Scheduler ui() {
        return mTestScheduler;
    }

    @Override
    public Scheduler computation() {
        return mTestScheduler;
    }

    @Override
    public Scheduler io() {
        return mTestScheduler;
    }

}

运行测试时出现此错误:

java.lang.NullPointerException
    at com.logab.customerui.login.LoginPresenter.login(LoginPresenter.java:85)
    at com.logab.customer.ui.login.LoginPresenterTest.testServerLoginSuccess(LoginPresenterTest.java:62)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498) 
    ....
    ....
    ...

[MockitoHint] LoginPresenterTest.testServerLoginSuccess (see javadoc for MockitoHint):
[MockitoHint] 1. Unused... -> at com.logap.customer.ui.login.LoginPresenterTest.testServerLoginSuccess(LoginPresenterTest.java:60)
[MockitoHint]  ...args ok? -> at com.logap.customer.ui.login.LoginPresenter.login(LoginPresenter.java:84)

处理该错误将转到此行:

.subscribeOn(getSchedulerProvider().io())

注意:我正在使用dagger2提供依赖项。

任何人都可以帮忙吗?谢谢。

1 个答案:

答案 0 :(得分:1)

您的代码为此行抛出NullPointerException

getDataManager().login(request)
                .subscribeOn(getSchedulerProvider().io())

因为它与您的登录方法调用的参数不匹配。

您必须调整测试,例如:
(使用ArgumentMatcher的{​​{1}})

eq

使用匹配器(假设LoginRequest对象的doReturn(Single.just(loginResponse)) .when(mMockDataManager) .login(eq(new LoginRequest(email, password))); equals已正确实现)应该可以解决您的问题。

或者,如果您不需要参数完全匹配, 您也可以改用hashcode