Issue
I'm writing tests for a simple Android application (it's a school project) and I'm having trouble testing the activity ContactListActivity which extends Android's ListActivity.
What I would like to test
Clicking the first item in ContactListActivity's ListView and checking if the ContactDetailActivity was started.
Problem
The list data comes from an SQLite database. For testing, I'm loading test data into the ListView, so the test won't be working with live data. Loading the test data works fine. Watching the emulator while running the test, I can see the activity being started and the test data appearing in the list. However, trying to access the first (and only) list item fails.
Test method
@UiThreadTest
public final void testLoadContactDetail() {
ListView list = activity.getListView();
assertNotNull(list);
ContactsListAdapter adapter = new ContactsListAdapter(
getInstrumentation().getContext(),
createData() // Creates an ArrayList of test data
);
list.setAdapter(adapter);
adapter.notifyDataSetChanged();
// list.getAdapter().getCount() is expectedly 1
// list.getChildCount() is unexpectedly 0
assertNotNull(list.getChildAt(0)); // Assertion fails
// (...)
}
As can be seen, I'm annotating the test with @UIThreadTest
to be able to manipulate view elements. A new ListAdapter is created with test data and set to the list. Then, adapter.notifyDataSetChanged()
makes sure that the list knows about the new data.
Question
How can I load test data from within an ActivityInstrumentationTestCase2 into a ListView so that the data will not only be displayed on screen, but actually "be there", meaning the list item can be fetched with list.getChildAt(0)
and be clicked?
Entire test case
public class ContactListActivityFunctionalTest extends
ActivityInstrumentationTestCase2<ContactListActivity> {
private ContactListActivity activity;
public ContactListActivityFunctionalTest() {
super(ContactListActivity.class);
}
protected void setUp() throws Exception {
super.setUp();
setActivityInitialTouchMode(false);
activity = getActivity();
}
protected void tearDown() throws Exception {
super.tearDown();
}
@UiThreadTest
public final void testLoadContactDetail() {
ListView list = activity.getListView();
assertNotNull(list);
ContactsListAdapter adapter = new ContactsListAdapter(
getInstrumentation().getContext(),
createData()
);
list.setAdapter(adapter);
adapter.notifyDataSetChanged();
assertNotNull(list.getChildAt(0));
// Anything beyond this point is never executed,
// because the above assertion fails, and I have no idea
// if this test code is correct at all.
ActivityMonitor monitor = getInstrumentation().addMonitor(
ContactDetailActivity.class.getName(), null, false
);
TouchUtils.clickView(this, list.getChildAt(0));
ContactDetailActivity contactDetailActivity =
(ContactDetailActivity)monitor.waitForActivityWithTimeout(2000);
assertNotNull(contactDetailActivity);
assertTrue(getInstrumentation().checkMonitorHit(monitor, 1));
contactDetailActivity.finish();
}
private List<ContactInterface> createData() {
ContactInterface contact = new Contact();
contact.setId(1L);
contact.setName("Unit Test").setPhone("0123456789").setPosition(3);
List<ContactInterface> contacts = new ArrayList<ContactInterface>();
contacts.add(contact);
return contacts;
}
}
Solution
I know I've asked how to load test data from within an ActivityInstrumentationTestCase2, but perhaps the answer to the question is to use ActivityUnitTestCase rather than ActivityInstrumentationTestCase2 in this particular case:
- General activity behaviour is being tested, rather than interaction with other components
- Well, it works...
Here is the rewritten, working test case that tests whether the ListView exists and whether the correct activity is started after a click on the list's first item.
public class ContactListActivityTest
extends ActivityUnitTestCase<ContactListActivity> {
private ContactListActivity activity;
public ContactListActivityTest() {
super(ContactListActivity.class);
}
protected void setUp() throws Exception {
super.setUp();
Intent intent = new Intent(
getInstrumentation().getTargetContext(), ContactListActivity.class
);
startActivity(intent, null, null);
activity = getActivity();
}
protected void tearDown() throws Exception {
super.tearDown();
}
public final void testItemClick() {
getInstrumentation().callActivityOnStart(activity);
getInstrumentation().callActivityOnResume(activity);
// Check if list exists
ListView list = activity.getListView();
assertNotNull("Intent was null", list);
// Load test data
ContactsListAdapter adapter = new ContactsListAdapter(
getInstrumentation().getContext(),
createData()
);
list.setAdapter(adapter);
adapter.notifyDataSetChanged();
assertEquals(2, adapter.getCount());
// Check if list has at least one item to click
View firstItem = list.getAdapter().getView(0, null, null);
assertNotNull(firstItem);
// Perform a click on the first item
list.performItemClick(
firstItem,
0,
list.getAdapter().getItemId(0)
);
// Check if the contact details activity got started
Intent intent = getStartedActivityIntent();
assertNotNull(intent);
assertEquals(
ContactDetailActivity.class.getName(),
intent.getComponent().getClassName()
);
}
private List<ContactInterface> createData() {
List<ContactInterface> contacts = new ArrayList<ContactInterface>();
ContactInterface contact = new Contact();
contact.setId(1L);
contact.setName("Jane Doe").setPhone("0123456789").setPosition(1);
contacts.add(contact);
ContactInterface contact2 = new Contact();
contact2.setId(2L);
contact2.setName("John Doe").setPhone("0234567890").setPosition(2);
contacts.add(contact2);
return contacts;
}
}
Answered By - jgxvx
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.