3

我已經實現了一個ListView,當點擊一個列表項時,將啓動一個新的Activity。當我手動測試時,它完美地工作。但是當我嘗試使用ActivityUnitTestCase進行自動測試時,我得到一個NullPointerException,好像ListView是空的。使用ActivityUnitTestCase測試Android ListView的點擊

MainActivity(部分):

public class MainActivity extends ListActivity { 

    @Override 
    protected void onResume() { 
    super.onResume(); 

    String[] items = new String[] {"item 1", "item 2"}; 
    ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, items); 
    setListAdapter(adapter); 

    getListView().setOnItemClickListener(new OnItemClickListener() { 

     @Override 
     public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 
     TextView clickedItem = (TextView) view; 
     CharSequence clickedItemText = clickedItem.getText(); // throws a NullPointerException when running testWithPerformItemClick()! 
     Intent intent = new Intent(MainActivity.this, ItemDisplayActivity.class); 
     intent.putExtra("parameter", clickedItemText); 
     startActivity(intent); 
     } 
    }); 
    } 
} 

測試代碼失敗:

public class MainActivityTest extends ActivityUnitTestCase<MainActivity> { 

    ListView listView; 
    View child0; 

    public MainActivityTest() { 
    super(MainActivity.class); 
    } 

    private void setUpTest() { 
    MainActivity activity = startActivity(new Intent(), null, null); 
    getInstrumentation().callActivityOnStart(activity); 
    getInstrumentation().callActivityOnResume(activity); 
    listView = (ListView) activity.findViewById(android.R.id.list); 
    child0 = listView.getChildAt(0); // returns null! 
    } 

    public void testWithPerformClick() { 
    setUpTest(); 

    child0.performClick(); // throws a NullPointerException! 

    Intent startedIntent = getStartedActivityIntent(); 
    assertEquals("item 1", startedIntent.getStringExtra("parameter")); 
    } 

    public void testWithPerformItemClick() { 
    setUpTest(); 
    long itemId = listView.getAdapter().getItemId(0); 

    listView.performItemClick(child0, 0, itemId); // throws a NullPointerException! 

    Intent startedIntent = getStartedActivityIntent(); 
    assertEquals("item 1", startedIntent.getStringExtra("parameter")); 
    } 

兩種測試方法失敗,因爲listView.getChildAt(0)返回null。爲什麼ListView是空的?我如何強迫它用正確的孩子更新自己?

+0

你試過['performItemClick()'](http://developer.android.com/reference/android/widget/AdapterView.html#performItemClick(android.view.View,%20int,% 20long))? – Ibungo

+0

使用'performItemClick()',代碼會變得更遠一些,直到'onItemClick'方法的'clickedItem.getText()'部分。一旦出現,因爲提供的'view'爲'null',因爲getChildAt(0)返回null,所以引發NPE。更新問題描述以使其更清楚。 – lacton

回答

0

這是因爲該列表視圖尚未繪製。在嘗試訪問其單元之前,應等待它被繪製

+0

這是有道理的。但是,你如何讓程序等待列表的繪圖?應該在'setUpTest()'方法中添加哪行代碼? – lacton

+0

我不得不說我正在尋找這方面的最佳做法。現在,我使用Thread.sleep調用。 – fewe

1

根據documentation,如果您更喜歡功能測試,則應使用ActivityInstrumentationTestCase2。要執行點擊,效果會更好。 @fewe的答案是正確的,你必須等待列表被繪製,等待片段被加載,你可以使用getInstrumentation()。waitForIdleSync();

嘗試類似這樣的東西。

public class ActivityTests extends 
    ActivityInstrumentationTestCase2<Activity> 

final ListView list = (ListView) mActivity.findViewById(R.id.listId); 
     assertNotNull("The list was not loaded", list); 
     getInstrumentation().runOnMainSync(new Runnable() { 
      @Override 
      public void run() { 

       list.performItemClick(list.getAdapter().getView(position, null, null), 
         position, list.getAdapter().getItemId(position)); 
      } 

     }); 

getInstrumentation().waitForIdleSync(); 

然後,你不能測試,例如,如果一個片段被加載。

mFragment frag = mActivity.getFragment(); 
    assertNotNull("Fragment was not loaded", frag);