繁体   English   中英

Robolectric和Retrofit - 等待回应

[英]Robolectric and Retrofit - wait for response

我想测试我的代码是否正确地从API下载数据(使用Retrofit)并在RecyclerView中显示它们。 为了做到这一点,我创建了一个拦截器,它嘲笑API(基于这个解决方案 )并创建了一个测试(使用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在主线程中执行所有runnable,而不是使用新线程,原始实现将如何执行。

另一种方法是与Espresso一起使用的IdlingResource概念。 每当您启动一个请求时,就会在单个对象上递增一个计数器,并在请求完成时递减计数器。 在测试中,您可以等到计数器为零。

简单的方法,但不好的做法将是一个简单的睡眠。

我发现使用Robolectric和Retrofit(带回调)的主要问题。 但是,当你如建立RestAdapterRestAdapter.Builder可以有条件地修改(NB从来没有使用在实际应用此配置):

if(singleThreaded){
    Executor executor = Executors.newSingleThreadExecutor();
    restAdapterBuilder.setExecutors(executor, executor);
}

通过为请求和回调添加此单线程执行程序,所有测试异步代码的标准方法(例如使用CountDownLatch )都将起作用。

另一种方法:

我一直在使用Awaitility工具取得了巨大的成功。 它与闩锁基本相同,但更具可读性。

在你的情况下:

@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();
    await().atMost(15, TimeUnit.SECONDS)
                      .until(responseIsSameAsCount(myListFragment, responseArray)
}


    private Callable<Boolean> responseIsSameAsCount(View myListFragment, JSONArray responseArray) {
    return new Callable<Boolean>() {
        @Override
        public Boolean call() throws Exception {
            return  ((RecyclerView) myListFragment.getView()
            .findViewById(R.id.rv_fruits)).getAdapter().getItemCount() == responseArray.length();
        }
    };
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM