Robolectric, Problems with clicking list items

android, android-testing, integration-testing, robolectric, testing

Solution

Try the helper method performItemClick:

Robolectric.shadowOf(listView).performItemClick(position); 

Problem

I have been struggling with this problem a bit, and I think I am not getting something fundamental about Robolectric. Usually some google searches can help me get to the bottom of this type of problem, but between that and looking at the sample code I am not finding anything of use. I am trying to emulate a click on a list view item and check that an activity is launched after the click. I keep getting back that the current activity I am testing is the resulting activity. I tried removing all of the list item clicking code and checking the resulting activity, and this came back as the InstallationListActivity that I am testing. So I came to the conclusion that the list view item is not being clicked, and I am just not sure why. The system logs that I have set up in the testing code below are the values that I expect them to be. The list is 13 items, and the getChildAt(0) returns the header. I would think that getting the first item (getChildAt(1)) and calling performClick on it or its child text view would launch my expected activity, but that doesn't seem to be the case. Anyway, here is the robolectric/testing code I am using: ``` @Before public void setUp() { mAppLaunch = new ApplicationLaunchActivity(); mAppLaunch.onCreate(null); mActivity = new InstallationListActivity(); mActivity.onCreate(null); } @Test public void shouldHaveNonEmptyInstallationList() throws Exception { assert(mActivity.installationListCount() > 0); } @Test public void shouldHaveSameNumberOfElements() throws Exception { ListView installationListView = (ListView) mActivity.getListView(); ShadowListView shadowListView = shadowOf(installationListView); assert(shadowListView.getChildCount() == mActivity.installationListCount()); } @Test public void pressingTheFirstItemInTheListShouldLaunchVenueListActivity() { ListView installationListView = (ListView) mActivity.findViewById(android.R.id.list); System.out.println("qty: " + installationListView.getChildCount()); System.out.println("class: " + installationListView.getChildAt(0).getClass()); System.out.println("class: " + installationListView.getChildAt(1).getClass()); System.out.println("class: " + installationListView.getChildAt(2).getClass()); System.out.println("class: " + installationListView.getChildAt(3).getClass()); System.out.println("class: " + installationListView.getChildAt(4).getClass()); LinearLayout firstItemLayout = (LinearLayout) installationListView.getChildAt(1); TextView firstItem = (TextView) firstItemLayout.getChildAt(0); ShadowTextView shadowFirstItem = shadowOf(firstItem); ShadowLinearLayout shadowLayout = (ShadowLinearLayout) shadowOf(firstItemLayout); shadowLayout.performClick(); shadowFirstItem.performClick(); clickOn(firstItem); clickOn(firstItemLayout); System.out.println("class: " + firstItemLayout.getChildAt(0).getClass()); System.out.println("Layout shadow" + shadowOf(firstItemLayout).getClass()); System.out.println("First Item Text: " + shadowFirstItem.getText()); ShadowActivity shadowActivity = shadowOf(mActivity); Intent startedIntent = shadowActivity.getNextStartedActivity(); assertNotNull(startedIntent); ShadowIntent shadowIntent = shadowOf(startedIntent); assertThat(shadowIntent.getComponent().getClassName(), equalTo(VenueListActivity.class.getName())); } } ``` Here is the layout's I am using to build the list view: ``` This is list.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"> <ListView android:id="@android:id/list" android:layout_width="fill_parent" android:layout_height="fill_parent" android:cacheColorHint="#00000000" android:background="@drawable/background"/> </LinearLayout> list_item.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/list_item" android:layout_height="fill_parent" android:layout_width="fill_parent"> <TextView android:id="@+id/list_item_text" style="@style/tw_list_font" android:layout_width="match_parent" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceLarge" android:gravity="center_vertical" android:paddingLeft="6dip" android:minHeight="?android:attr/listPreferredItemHeight" /> </LinearLayout> ``` And here is the code that initializes the list: ``` InstallationListActivity.java setContentView(R.layout.list); final ListView installationListView = getListView(); LayoutInflater inflater = getLayoutInflater(); ViewGroup header = (ViewGroup) inflater.inflate(R.layout.header, installationListView, false); TextView headerText = (TextView) header.findViewById(R.id.header_text); headerText.setText("Installations On Live"); // TODO: This should not be hardcoded installationListView.addHeaderView(header, null, false); setListAdapter(new ArrayAdapter<Installation>(this, R.layout.list_item, R.id.list_item_text, mInstallations)); // Click event installationListView.setClickable(true); installationListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int position, long arg1) { Installation installationClicked = (Installation) installationListView.getItemAtPosition(position); if (LOCAL_LOG) { Log.d(LOG_TAG, "Installation: " + installationClicked.toString() + " clicked."); Log.d(LOG_TAG, installationClicked.toString() + " has installationDirectory: " + installationClicked.rootDir); } AppState.installation = installationClicked; AppState.serverInstallationName = installationClicked.rootDir; Intent venueListIntent = new Intent(InstallationListActivity.this, VenueListActivity.class); startActivity(venueListIntent); } }); ``` Any help is much appreciated! Thanks a ton!

Original source