Как проверить активность списка с помощью тестовых данных?
Я пишу тесты для простого приложения для Android (это школьный проект), и у меня возникли проблемы с тестированием активности ContactListActivity, которая расширяет ListActivity Android.
Что я хотел бы проверить
Щелчок по первому элементу в списке ContactListActivity и проверка запуска ContactDetailActivity.
Задача
Данные списка поступают из базы данных SQLite. Для тестирования я загружаю тестовые данные в ListView, поэтому тест не будет работа с живыми данными. Загрузка тестовых данных работает нормально. Наблюдая за эмулятором во время выполнения теста, я вижу, как запускается действие и тестовые данные появляются в списке. Однако попытка получить доступ к первому (и только) элементу списка завершается неудачей.
Метод испытаний
@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
// (...)
}
Как можно видеть, я аннотирую тест с помощью
@UIThreadTest, чтобы иметь возможность манипулировать элементами представления. Новый ListAdapter создается с тестовыми данными и устанавливается в список. Затем adapter.notifyDataSetChanged() удостоверяется, что список знает о новые данные.Вопрос
Как я могу загрузить тестовые данные из ActivityInstrumentationTestCase2 в ListView, чтобы данные не только отображались на экране, но и фактически "были там", то есть элемент списка можно извлечь с помощью list.getChildAt(0) и щелкнуть по нему?
Весь тестовый случай
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;
}
}
2 ответов:
Похоже, что метод
listView.getChildAtвозвращает видимые представления. https://stackoverflow.com/a/6767006/693752Итак, я предполагаю, что элемент еще не виден. Нет, поскольку getChildCount возвращает 0. Может быть, вам следует либо :
- подождите немного, прежде чем утверждать. Ладно, это грязно, но тестирование пользовательского интерфейса нуждается в этом когда-нибудь.
- разместите assert внутри runnable в потоке пользовательского интерфейса, чтобы он выполнялся после выполнения listview. Это превратит ваш тест в нечто большее. немного сложнее, так как вам придется синхронизировать будущий запускаемый и текущий тестовый поток с обратным отсчетом. И для этого, вы должны рассмотреть возможность не использовать @UIThreadTest.
Я знаю, что спрашивал, как загрузить тестовые данные из ActivityInstrumentationTestCase2, но, возможно, ответ на этот вопрос заключается в использовании ActivityUnitTestCase, а не ActivityInstrumentationTestCase2 в данном конкретном случае:
- тестируется общее поведение деятельности, а не взаимодействие с другими компонентами
- Ну, это работает...
Вот переписанный рабочий тестовый случай, который проверяет, существует ли ListView и является ли он правильным. действие запускается после щелчка на первом элементе списка.
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; } }
Comments