android - 如何用测试数据测试一个ListActivity?

标签 android android-testing

我正在为一个简单的 Android 应用程序(这是一个学校项目)编写测试,但我在测试扩展 Android 的 ListActivity 的 Activity ContactListActivity 时遇到了问题。

我想测试什么

单击 ContactListActivity 的 ListView 中的第一项并检查 ContactDetailActivity 是否已启动。

问题

列表数据来自 SQLite 数据库。为了进行测试,我将测试数据加载到 ListView 中,因此测试不会使用实时数据。加载测试数据工作正常。在运行测试时观察模拟器,我可以看到正在启动的 Activity 和列表中出现的测试数据。但是,尝试访问第一个(也是唯一一个)列表项失败。

测试方法

@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 注释测试,以便能够操作 View 元素。使用测试数据创建一个新的 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;
    }
}

最佳答案

看起来 listView.getChildAt 方法返回可见 View 。 https://stackoverflow.com/a/6767006/693752

所以,我的猜测是该项目还不可见。没有一个是因为 getChildCount 返回 0。也许你应该:

  • 在断言之前稍等一下。好吧,它很脏,但 UI 测试有时需要它。
  • 将 assert 发布到 ui 线程上的 runnable 中,以便它在 listview 执行后执行。这将使您的测试变得更复杂一些,因为您必须同步 future 的可运行线程和当前测试线程 countDownLatch。为此,您应该考虑不使用 @UIThreadTest。

关于android - 如何用测试数据测试一个ListActivity?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20708200/

相关文章:

android - 我如何让 Gradle for Android 从其他测试代码中找到一个库的测试代码?

android - 基于 BLE 的 Android 应用的密封测试

android - 如何获得 ListView 的焦点子项?

Android NDK 同时使用 C 和 C++ 文件

android - 如何为 create-react-native-app 生成 apk 文件(使用 EXPO.IO 组件)

java - 两种不同的参数类型(将对象转换为类型)

java - 如何在使用 Robolectric 时监视 Activity

Android Espresso - 等待直到显示对话框

android - 我们如何才能自动只在较新的 Android 版本上运行测试?

android - 是否可以刷新 fragment 的 View