我想测试我的代码是否正确地从API下载了数据(使用Retrofit)并将其显示在RecyclerView中.为了做到这一点,我创建了一个模仿API的拦截器(基于this solution)并创建了一个测试(使用Robolectric):
@Test
public void listLoadedCorrectlyTest() {
MyListFragment myListFragment = new MyListFragment();
Bundle args = new Bundle();
FragmentTestUtil.startFragment(myListFragment);
Robolectric.flushForegroundThreadScheduler();
JSONArray responseArray = new JSONArray();
try {
responseArray = new JSONArray(ApiInterceptor.MOCK_RESPONSE);
} catch (JSONException e) {
Log.e("JSON", e.getMessage());
}
int adapterItemCount = ((RecyclerView) myListFragment.getView()
.findViewById(R.id.rv_fruits)).getAdapter().getItemCount();
assertThat(adapterItemCount).isEqualTo(responseArray.length());
}
问题是测试有时会通过,有时会失败.我已经调试了代码,我知道这是因为MyListFragment中的数据已使用Retrofit的enqueue()方法加载到rv_fruits RecyclerView中.我如何等待Retrofit回调,以便在将数据加载到RecyclerView之后检查断言?
解决方法:
Robolectric尝试使所有执行同步,因为异步代码会导致不稳定的测试.如果您使用AsynTask之类的标准工具,但改装却不做,则效果很好.
一种方法是隐藏某些Retrofit(或OkHttp)类,这些类在新线程中执行请求,而直接执行它们.例如,ShadowAsyncTask在主线程中执行所有可运行的命令,而不是像原来的实现那样使用新线程.
另一种方法是Espresso使用的IdlingResource概念.每当您启动请求时,然后在单例对象上增加计数器,并在请求完成时减少计数器.在测试中,您可以等待直到计数器为零.
简单的方法,但不好的做法将是一个简单的睡眠.