测试包含Retrofit的MVP Android

时间:2015-07-03 14:16:11

标签: android unit-testing mockito mvp retrofit

我正在使用改造来开发基于MVP模式的应用程序来执行网络连接。我想对我的演示者进行单元测试,但它失败了。

在我的app中,dataView实现了由Mockito模拟的DataView。在 DataPresenter方法onViewCreated实例中的MyApi来自MyApplication并执行请求。匿名Subscriber<Data> onNext在showData(Data data)上调用dataView。不幸的是Mockito.verify(dataView).showData(data)未通过测试。我嘲笑我的自我改造客户以确定的方式回应。

以下代码:

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);
    }
}

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();

        }
    });
    ;
}

我的测试用例:

    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());
    }

测试失败&#34;想要但未被调用: dataView.showData(...&#34;。

有趣的Response execute()MockClient中被调用,但onNext(Data data)中包含的订阅者DataPresenterImpl则没有。有任何想法吗?我想这是请求异步的问题。

1 个答案:

答案 0 :(得分:0)

问题在于工作正在被发送到另一个线程并且无法验证最新情况。我的解决方案是创建一个调度程序工厂并将其模拟出来并返回主线程进行测试 像这些。类似的东西:

public class schedulerFactory {

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

然后在你的测试中你会写这样的东西:

@Mock SchedulerFactory factory

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

}

一般来说,最好在同一个线程中运行所有代码进行测试