2016-04-11 21 views
2

私のコードがRetrofitを使用してAPIからデータを正しくダウンロードしていることを確認し、それらをRecyclerViewに表示するかどうかをテストしたいと思います。これを行うために、私は、API(this solutionに基づか)を皮肉っインターセプタを作成し、(Robolectric使用して)テスト作成:RobolectricとRetrofit - 応答待ち

@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_fruitsRecyclerViewにロードされているためです。データがRecyclerViewにロードされた後にアサーションがチェックされるように、どのようにRetrofitコールバックを待つことができますか?

+0

は、あなたのフラグメントのコードを表示することができますか?あなたはそこでネットワーキングを模倣できますか? –

答えて

1

Robolectricは、非同期コードがフレークテストにつながるため、すべての実行を同期させようとします。これは、AsynTaskのような標準的なものを使用していて、改造しないとうまく動作します。

1つのアプローチは、新しいスレッドで要求を実行し、代わりに直接実行するRetrofit(またはOkHttp)クラスをシャドウすることです。たとえば、ShadowAsyncTaskは、新しいスレッドを使用せずにメインスレッドですべての実行可能ファイルを実行します。

もう1つのアプローチは、エスプレッソで使用されるIdlingResourceのコンセプトです。要求を開始すると、シングルトンオブジェクト上のカウンタがインクリメントされ、要求が完了するとカウンタが減少します。テストでは、カウンタがゼロになるまで待つことができます。

簡単なアプローチですが、悪い習慣は簡単な睡眠になります。

+0

この場合、 'CountDownLatch'を使うのはいい考えですと思いますか?それはRobolectricで動作しますか? – fragon

+1

基本的にCountDownLatchはRobolectricで動作します。 1つの理由は、countDown()呼び出しの予想数を指定する必要があるということです。これはあなたのニーズに十分かもしれません! CountDownLatchにはcountUp()メソッドはありません。これは、リクエストの数がわからない場合に必要になる可能性があります。 countUp()が必要な場合は、http://stackoverflow.com/a/14260716/3619179を試してください。 – nenick

1

Robolectric with Retrofit(コールバック付き)を使用する際に重大な問題が見つかりました。ただし、あなたがたとえば両方の要求のため、この単一スレッドのexecutorを追加することにより

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

とテスト非同期コードへのすべての標準的なアプローチをコールバック:あなたは条件付きで(NBは、実際のアプリケーションでは、この設定を使用することはありません)、それを修正することができRestAdapter.BuilderRestAdapterを設定します(例えば、CountDownLatchを使用して)動作します。

1

別のアプローチ:

私は大きな成功を収めて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(); 
     } 
    }; 
} 
関連する問題