Как проверить активность списка с помощью тестовых данных?



Я пишу тесты для простого приложения для 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;
}
}
615   2  

2 ответов:

Похоже, что метод listView.getChildAt возвращает видимые представления. https://stackoverflow.com/a/6767006/693752

Итак, я предполагаю, что элемент еще не виден. Нет, поскольку getChildCount возвращает 0. Может быть, вам следует либо :

  • подождите немного, прежде чем утверждать. Ладно, это грязно, но тестирование пользовательского интерфейса нуждается в этом когда-нибудь.
  • разместите assert внутри runnable в потоке пользовательского интерфейса, чтобы он выполнялся после выполнения listview. Это превратит ваш тест в нечто большее. немного сложнее, так как вам придется синхронизировать будущий запускаемый и текущий тестовый поток с обратным отсчетом. И для этого, вы должны рассмотреть возможность не использовать @UIThreadTest.

Я знаю, что спрашивал, как загрузить тестовые данные из ActivityInstrumentationTestCase2, но, возможно, ответ на этот вопрос заключается в использовании ActivityUnitTestCase, а не ActivityInstrumentationTestCase2 в данном конкретном случае:

  1. тестируется общее поведение деятельности, а не взаимодействие с другими компонентами
  2. Ну, это работает...

Вот переписанный рабочий тестовый случай, который проверяет, существует ли 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

    Ничего не найдено.