Android MVP testing with upgradeability

I am developing an application based on MVP pattern using modification to work on the web. I want to unit test my presenter, but it doesn't work.

In my application, the DataView implements DataView

that mocks Mockito. In DataPresenter

a onViewCreated

method, an MyApi

instance gets from MyApplication

and executes the request. Anonymous Subscriber<Data>

onNext calls showData(Data data)

on DataView

. Unfortunately the Mockito.verify(dataView).showData(data)

test doesn't pass. I mocked the modified client's self by responding in a 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());
    }

      

The test fails with the error "Required but not called: dataView.showData (...".

What's interesting Response execute()

is called in MockClient

, but onNext(Data data)

in the subscriber included in DataPresenterImpl

, not. Any ideas? I guess the problem is with the asynchronous request.

+3


source to share


1 answer


The problem is that the work is being sent to a different thread and the mockito cant check what is going on. My solution would be to create a factory planner and mock it and return the main thread for tests like this. Something like:

public class schedulerFactory {

public Scheduler io() {
 return Schedulers.io();
}
 //etc
}

      

then in your test you should write something like this:



@Mock SchedulerFactory factory

@Before
public void setUp() {
 when(factory.io()).thenReturn(Schedulers.mainThread());

}

      

in general it's a good idea to run all the code in the same thread for testing

0


source







All Articles