2012-01-25 12 views
4

ListFragmentが含まれているアクティビティの機能をテストしたいのですが、これについてどうすればよいかわかりません。私はたくさん試しましたが、何も動作していないようです。ListFragmentを含むAndroidアクティビティの機能をテストするにはどうすればよいですか?

だから私はテストしたい活動はListFragmentが含まれており、このListFragmentLoaderManager.LoaderCallbacksCursorLoaderを使用して移入されます。このCursorLoaderContentProviderを照会し、onLoadFinished()メソッドはCursorListViewListAdapterに入れ替えます。

私がテストで達成したいのは、アクティビティを開始し、ListViewに正しいデータが入力されているかどうかをテストすることです。 ContentProviderの内容は、ServiceというWebサービスから取得したコンテンツに基づいているため、ContentProviderを試して、テストデータが期待どおりのものであることを確認する必要があります。しかし、これは完了したよりも簡単です。私はあらゆる種類の問題にぶつかりました。

ほとんどの問題は、私のデータがAsyncTaskによってCursorLoade rによってロードされていることに起因すると考えられます。 onCreate()メソッドのローダーは私のListFragmentですが、AsyncTaskのロードが完了するのを待たずにonCreate()が終了した後にテストが実行されます。テストが実行される前にロードが完了していないため、テストが失敗します。

これは私のテストクラスである:

public class TopscorersActivityTest extends ActivityUnitTestCase<TopscorersActivity> { 

    public static final int TEST_POSITION = 1; 
    public static final String TEST_NAME = "name"; 
    public static final String TEST_CLUB = "club"; 
    public static final int TEST_GOALS = 2; 

    private Intent mStartIntent; 
    private ListView mListView; 
    private Context mContext; 
    private ContentResolver mContentResolver; 

    public TopscorersActivityTest() { 
     super(TopscorersActivity.class); 
    } 

    @Override 
    protected void setUp() throws Exception { 
     super.setUp(); 
     mStartIntent = new Intent(); 

     mContext = new RenamingDelegatingContext(getInstrumentation().getTargetContext(), "test"); 
     mContentResolver = mContext.getContentResolver(); 
     setActivityContext(mContext); 

     // Setup database fixture 
     ContentValues values = new ContentValues(); 
     values.put(Topscorers.TOPSCORER_POSITION, TEST_POSITION); 
     values.put(Topscorers.TOPSCORER_NAME, TEST_NAME); 
     values.put(Topscorers.TOPSCORER_CLUB, TEST_CLUB); 
     values.put(Topscorers.TOPSCORER_GOALS, TEST_GOALS); 

     mContentResolver.delete(Topscorers.CONTENT_URI, null, null); 
     mContentResolver.insert(Topscorers.CONTENT_URI, values); 
    } 

    public void testPreConditions() { 
     startActivity(mStartIntent, null, null); 
     assertNotNull(getActivity()); 

     mListView = (ListView) getActivity().findViewById(android.R.id.list); 
     assertNotNull(mListView); 

     Cursor cursor = mContentResolver.query(Topscorers.CONTENT_URI, null, null, null, null); 
     assertEquals(1, cursor.getCount()); 
    } 

    public void testListPopulatedCorrectly() { 
     startActivity(mStartIntent, null, null); 
     getInstrumentation().waitForIdleSync(); 

     ListView listView = (ListView) getActivity().findViewById(android.R.id.list); 
     assertEquals(1, listView.getCount()); 
    } 
} 

testPreConditions()テストは成功しますが、listView.getCount() 0を返します。

がどのように私は私が望むものを達成することができますので、testListPopulatedCorrectly()は失敗?私はテストコードで正しい方向に進んでいますか?それとも別のアプローチをとるべきですか?もしそうなら、何?

+0

誰もいませんか?私のテストのアプローチに関する一般的な発言でさえ、私は立ち往生しているので、今評価されています。 –

答えて

2

私の質問では何の応答も受けていないので、自分の質問に答えます。私は私の質問のコードサンプルで使われているものとは別のアプローチをとることに決めました。私の新しいアプローチの基本的な概要は次のとおりです。

  • は、私は自分のコードに注入MockHttpClientクラスを作成しActivityInstrumentationTestCase2

  • に私のベースのテストクラスを切り替え、そしてこのMockHttpClientは成功HttpResponseとを返します。私のJSON什器データを含む応答エンティティ。 MockHttpClientクラスはHttpClientインターフェイスを実装し、すべてのメソッドに対してnullを返しますが、​​メソッドはHttpResponseオブジェクトを返す必要があります。

  • ListFragment私は、BroadcastReceiverを登録してデータ検索サービスが終了したことを確認しているため、私もBroadcastReceiverを私のテストに登録します。ブロードキャストが受信されるまで私はCountDownLatchでテストをブロックします。

  • ブロードキャストを受信すると、Thread.sleep(500)を使用して、アクティビティをListViewに更新します。その後、私はListViewに対して私の主張を実行します。

  • アサーションが失敗したときにテストを最大5回実行するFlakyTest(tolerance=5)で私のテストに注釈を付けました。

これは良いアプローチであるかどうかわかりませんので、お気軽にコメントしてください。しかし、今のところそれは動作します。その@ Jan- Thread.wait(500)呼び出しを使用するのではなく、

テストクラス

public class TopscorersActivityTest extends ActivityInstrumentationTestCase2<TopscorersActivity> { 

    public static final String JSON = "[" 
     + "{\"position\": 1, \"name\": \"Bas Dost\", \"club\": \"sc Heerenveen\", \"goals\": \"16\" }," 
     + "{\"position\": 2, \"name\": \"Dries Mertens\", \"club\": \"PSV\", \"goals\": \"13\"}," 
     + "{\"position\": 3, \"name\": \"Luuk de Jong\", \"club\": \"FC Twente\", \"goals\": \"12\"}" 
     + "]"; 

    private TopscorersActivity mActivity; 
    private ListView mListView; 

    public TopscorersActivityTest() { 
     super("com.example.package", TopscorersActivity.class); 
    } 

    @Override 
    protected void setUp() throws Exception { 
     super.setUp(); 
     ConnectivityUtils.setHttpClient(MockHttpClient.createInstance(JSON)); 
     mActivity = getActivity(); 
     mListView = (ListView) getActivity().findViewById(android.R.id.list); 
    } 

    @Override 
    protected void tearDown() throws Exception { 
     super.tearDown(); 
     ConnectivityUtils.setHttpClient(null); 
    } 

    @MediumTest 
    public void testPreconditions() { 
     assertNotNull(mActivity); 
     assertNotNull(mListView); 
     assertEquals(0, mListView.getFirstVisiblePosition()); 
    } 

    @FlakyTest(tolerance=5) 
    @LargeTest 
    public void testListItemsPopulatedCorrectly() throws InterruptedException { 
     waitForBroadcast(mActivity, TopscorersService.BROADCAST_ACTION, Intent.CATEGORY_DEFAULT); 

     assertEquals(3, mListView.getCount()); 

     // First list item 
     View view = mListView.getChildAt(0); 
     assertNotNull(view); 

     TextView positionTextView = (TextView) view.findViewById(R.id.topscorerPositionTextView); 
     TextView nameTextView = (TextView) view.findViewById(R.id.topscorerNameTextView); 
     TextView goalsTextView = (TextView) view.findViewById(R.id.topscorerGoalsTextView); 

     assertEquals("1", positionTextView.getText()); 
     assertEquals("16", goalsTextView.getText()); 
     assertEquals(
      Html.fromHtml("Bas Dost<br /><i>sc Heerenveen</i>").toString(), 
      nameTextView.getText().toString() 
     ); 

     // Second list item 
     view = mListView.getChildAt(1); 
     assertNotNull(view); 

     positionTextView = (TextView) view.findViewById(R.id.topscorerPositionTextView); 
     nameTextView = (TextView) view.findViewById(R.id.topscorerNameTextView); 
     goalsTextView = (TextView) view.findViewById(R.id.topscorerGoalsTextView); 

     assertEquals("2", positionTextView.getText()); 
     assertEquals("13", goalsTextView.getText()); 
     assertEquals(
       Html.fromHtml("Dries Mertens<br /><i>PSV</i>").toString(), 
       nameTextView.getText().toString() 
     ); 

     // Third list item 
     view = mListView.getChildAt(2); 
     assertNotNull(view); 

     positionTextView = (TextView) view.findViewById(R.id.topscorerPositionTextView); 
     nameTextView = (TextView) view.findViewById(R.id.topscorerNameTextView); 
     goalsTextView = (TextView) view.findViewById(R.id.topscorerGoalsTextView); 

     assertEquals("3", positionTextView.getText()); 
     assertEquals("12", goalsTextView.getText()); 
     assertEquals(
       Html.fromHtml("Luuk de Jong<br /><i>FC Twente</i>").toString(), 
       nameTextView.getText().toString() 
     ); 
    } 

    private void waitForBroadcast(Context context, String action, String category) throws InterruptedException { 
     final CountDownLatch signal = new CountDownLatch(1); 

     IntentFilter intentFilter = new IntentFilter(action); 
     intentFilter.addCategory(category); 
     BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { 
      @Override 
      public void onReceive(Context context, Intent intent) { 
       signal.countDown(); 
      } 
     }; 

     context.registerReceiver(broadcastReceiver, intentFilter); 
     signal.await(1500, TimeUnit.MILLISECONDS); 
     context.unregisterReceiver(broadcastReceiver); 
     Thread.sleep(500); 
    } 
} 

MOCK HTTPクライアントクラス

public class MockHttpClient implements HttpClient { 
    private HttpResponse mHttpResponse; 

    /** 
    * A MockHttpClient with an HTTP 1.1 200 OK response 
    * 
    * @param response 
    * @return 
    * @throws UnsupportedEncodingException 
    */ 
    public static HttpClient createInstance(String response) 
      throws UnsupportedEncodingException { 

     return createInstance(200, "OK", response); 
    } 

    /** 
    * A MockHttpClient with an HTTP 1.1 response 
    * 
    * @param statusCode 
    * @param reasonPhrase 
    * @param response 
    * @return 
    * @throws UnsupportedEncodingException 
    */ 
    public static HttpClient createInstance(int statusCode, String reasonPhrase, String response) 
     throws UnsupportedEncodingException { 

     return createInstance(HttpVersion.HTTP_1_1, statusCode, reasonPhrase, response); 
    } 

    /** 
    * 
    * @param version 
    * @param statusCode 
    * @param reasonPhrase 
    * @param response 
    * @return 
    * @throws UnsupportedEncodingException 
    */ 
    public static HttpClient createInstance(ProtocolVersion version, int statusCode, String reasonPhrase, String response) 
      throws UnsupportedEncodingException { 

     StatusLine statusLine = new BasicStatusLine(version, statusCode, reasonPhrase); 
     HttpResponse httpResponse = new BasicHttpResponse(statusLine); 
     HttpEntity httpEntity = new StringEntity(response); 
     httpResponse.setEntity(httpEntity); 
     return new MockHttpClient(httpResponse); 
    } 

    /** 
    * Constructor. 
    * 
    * @param httpResponse 
    */ 
    private MockHttpClient(HttpResponse httpResponse) { 
     mHttpResponse = httpResponse; 
    } 

    /** 
    * 
    * @param request 
    * @return 
    */ 
    public HttpResponse execute(HttpUriRequest request) { 
     return mHttpResponse; 
    } 

    @Override 
    public HttpResponse execute(HttpUriRequest request, HttpContext context) 
      throws IOException, ClientProtocolException { 
     return mHttpResponse; 
    } 

    @Override 
    public HttpResponse execute(HttpHost target, HttpRequest request) 
      throws IOException, ClientProtocolException { 
     return mHttpResponse; 
    } 

    @Override 
    public <T> T execute(HttpUriRequest arg0, 
      ResponseHandler<? extends T> arg1) throws IOException, 
      ClientProtocolException { 
     return null; 
    } 

    @Override 
    public HttpResponse execute(HttpHost target, HttpRequest request, 
      HttpContext context) throws IOException, 
      ClientProtocolException { 
     return mHttpResponse; 
    } 

    @Override 
    public <T> T execute(HttpUriRequest arg0, 
      ResponseHandler<? extends T> arg1, HttpContext arg2) 
      throws IOException, ClientProtocolException { 
     return null; 
    } 

    @Override 
    public <T> T execute(HttpHost arg0, HttpRequest arg1, 
      ResponseHandler<? extends T> arg2) throws IOException, 
      ClientProtocolException { 
     return null; 
    } 

    @Override 
    public <T> T execute(HttpHost arg0, HttpRequest arg1, 
      ResponseHandler<? extends T> arg2, HttpContext arg3) 
      throws IOException, ClientProtocolException { 
     return null; 
    } 

    @Override 
    public ClientConnectionManager getConnectionManager() { 
     return null; 
    } 

    @Override 
    public HttpParams getParams() { 
     return null; 
    } 
} 
4

:私の答えは、私のテストのための新しいコードを締結するために、ヘンクはユニットテストで、次のようにしてDataSetObserverを使用しました。

mListView.getAdapter().registerDataSetObserver(new DataSetObserver() { 
     @Override 
     public void onChanged() { 
      assertTrue(mListView.getCount() > 0); 
     } 
    }); 

これを行うと、変更を正確に取得できます。