vendredi 3 juillet 2015

Testing MVP Android with Retrofit included

I'm developing application based on MVP pattern using retrofit to perform networking. I want to unit test my presenter but it fails.

In my app dataView implements DataView which is mocked by Mockito. In DataPresenter in onViewCreated method MyApi instance is get from MyApplication and it performs request. Anonymous Subscriber<Data> onNext calls showData(Data data) on dataView. Unfortunatelly Mockito.verify(dataView).showData(data) fails the test. I mocked retrofit client by my self to response in deterministic way.

Code below:

public class DataFragment extends ProgressFragment implements DataView {

    protected DataPresenter mDataPresenter;

    //[...] initialization arguments boilerplate etc.


    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mDataPresenter.onViewCreated(mId);
        //[...]
    }

    @Override
    public void startLoading() {
        setContentShown(false);
    }

    @Override
    public void stopLoading() {
        setContentShown(true);
    }

    @Override
    public void showData(Data data) {
        setContentEmpty(false);
        //[...] present data
    }

    @Override
    public void showError() {
        setContentEmpty(true);
        setEmptyText(R.string.unknown_error);
    }
}

In DataPresenter:

@Override
public void onViewCreated(long id) {
    getView().startLoading();
    MyApplication.getInstance().getMyApi().checkIn(User.getUser().getFormattedTokenForRequest(),
            (int) id).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io()).subscribe(new Subscriber<Data>() {
        @Override
        public void onCompleted() {

        }

        @Override
        public void onError(Throwable e) {
            getView().showError();
            getView().stopLoading();
        }

        @Override
        public void onNext(Data data) {
            getView().showData(data);
            getView().stopLoading();

        }
    });
    ;
}

My test case:

    public static final String GOOD_RESPONSE = "[Data in JSON]"
    public static final int GOOD_STATUS = 201;

    @Mock
    DataView mDataView;

    @Mock
    MyApplication app;

    @Mock
    SharedPreferencesManager mSharedPreferencesManager;

    DataPresenter mDataPresenter;

    @Before
    public void setUp() throws Exception {
        mDataPresenter = new DataPresenterImpl(mDataView);
        MyApplication.setInstance(app);
        Mockito.when(app.getSharedPreferencesManager()).thenReturn(mSharedPreferencesManager);
        Mockito.when(mSharedPreferencesManager.getUser()).thenReturn(null);
    }

    @Test
    public void testCase() throws Exception {
        RestAdapter adapter = (new RestAdapter.Builder()).setEndpoint(URL)
                .setClient(new MockClient(GOOD_RESPONSE, GOOD_STATUS))
                .build();
        Mockito.when(app.getMyApi()).thenReturn(adapter.create(MyApi.class));
        mCheckInPresenter.onViewCreated(3);
        Mockito.verify(checkInView).startLoading();
        Mockito.verify(checkInView).showData(new Data());
    }

Test fails on "Wanted but not invoked: dataView.showData(..." .

What is interesting Response execute() is called in MockClient but onNext(Data data) in subscriber included in DataPresenterImpl is not. Any ideas? I guess it is a problem with request being asynchronous.

Aucun commentaire:

Enregistrer un commentaire