Testing a click on an Android ListView with ActivityUnitTestCase
Asked Answered
C

2

3

I have implemented a ListView that starts a new Activity when a list item is clicked. When I test it manually, it works perfectly. But when I try to do an automated test with ActivityUnitTestCase, I get a NullPointerException as though the ListView was empty.

MainActivity (partial):

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);
      }
    });
  }
}

The test code that fails:

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"));
  }

Both test methods fail because listView.getChildAt(0) returns null. Why is the ListView empty? How can I force it to update itself with the right children?

Cooney answered 31/8, 2013 at 10:23 Comment(2)
Have you tried the performItemClick()?Nipha
Using performItemClick(), the code gets a little bit farther, up to the clickedItem.getText() part of the onItemClick method. Once there, a NPE is raised because the provided view is null (because getChildAt(0) returns null). Updating the issue description to make this clearer.Cooney
N
1

According to the documentation, If you prefer a functional test you should use ActivityInstrumentationTestCase2. To perform a click it works better. The @fewe answer is right, you have to wait the list to be drawn, to wait the fragment to be loaded you can use getInstrumentation().waitForIdleSync();

Try something like this.

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();

Then you cant test, for example, if a fragment was loaded.

  mFragment frag = mActivity.getFragment();
  assertNotNull("Fragment was not loaded", frag);
Neuburger answered 27/5, 2014 at 17:38 Comment(0)
D
0

This is because the listview isn't drawn yet. You should wait for it to be drawn before trying to access its cells

Distilled answered 15/11, 2013 at 15:42 Comment(2)
That would make sense. But how do you make the program wait for the list's drawing? What line of code should be added in the setUpTest() method?Cooney
I have to say I am looking for a best practice on this matter as well. For now, I use a Thread.sleep call.Distilled

© 2022 - 2024 — McMap. All rights reserved.