测试ViewPager(和CursorLoader)与Robolectric测试、ViewPager、Robolectric、CursorLoader

2023-09-04 08:34:35 作者:荼蘼

有谁知道如何使用Robolectric测试以下设置?

含有ViewPager片段,数据加载有CursorLoader

通过下面的code时,CursorLoader永远不会被推入该视图寻呼机适配器。 我陷在等待()电话。

EventsFragmentTest.java:

  @RunWith(CustomRobolectricTestRunner.class)
公共类EventsFragmentTest扩展AbstractDbAndUiDriver
{
    //该元素在视图中寻呼机我们正在测试
    私有静态最终诠释的test_index = 0;

    保护SherlockFragmentActivity mActivity;
    保护EventsFragment_ mFragment;

    @覆盖
    @之前
    公共无效设置()抛出异常
    {
        //创建活动举行片段
        this.mActivity = CustomRobolectricTestRunner.getActivity();

        //创建并启动片段
        this.mFragment =新EventsFragment_();
    }

    @测试
    公共无效sanityTest()
    {
        //创建一个事件
        最终事件事件= this.createEvent();

        //创建模拟光标装载机
        最后光标光标= this.createMockEventCursor(事件);
        this.mFragment.setCursorLoader(模拟(CursorLoader.class));
        当(this.mFragment.getCursorLoader()loadInBackground()。)thenReturn(光标)。
        CustomRobolectricTestRunner.startFragment(this.mActivity,this.mFragment);

        等待()atMost(5秒)。直到(this.isCursorLoaderLoaded(),equalTo(真))。

        //检查显示的数据
        最后的TextView标题= this.getTextView(R.id.event_view_title);
        最后的TextView文本= this.getTextView(R.id.event_view_text);

        //存在,可见是足够了
        this.getImageView(R.id.event_view_image);

        assertThat(title.getText()的toString(),equalTo(event.getTitle())。);
        assertThat(text.getText()的toString(),是(event.getText()));

        // 清理
        cursor.close();
    }

    @覆盖
    受保护的视图getRootView()
    {
        返程((ViewPager)this.mFragment.getView()findViewById(R.id.events_pager)。)getChildAt(的test_index)。
    }

    私人可赎回<布尔> isCursorLoaderLoaded()
    {
        回到新的可赎回<布尔>()
        {
            公共布尔调用()抛出异常
            {
                返回EventsFragmentTest.this.mFragment.isCursorLoaderLoaded(); //所必须满足的条件
            }
        };
    }

    / **
     *创建一个事件
     *
     * @返回
     * /
    保护事件CreateEvent的()
    {
        //创建一个随机事件
        最终事件事件=新的事件();
        event.setImage(空);
        event.setLink(/一些/链接/+ RandomUtils.getRandomString(5)); // $ NON-NLS-1 $
        event.setResourceUri(/ REST / URI /+ RandomUtils.getRandomDouble()); // $ NON-NLS-1 $
        event.setText(这是一个测试对象+ RandomUtils.getRandomString(5)); // $ NON-NLS-1 $
        回到事件;
    }

    受保护的光标createMockEventCursor(最终事件的事件)
    {
        //创建一个模拟指针。
        最后光标光标=新CursorWrapper(模拟(MockCursor.class));

        当(cursor.getCount())thenReturn(1)。
        when(cursor.getString(cursor.getColumnIndexOrThrow(EventTable.COLUMN_TEXT))).thenReturn(event.getText());
        when(cursor.getString(cursor.getColumnIndexOrThrow(EventTable.COLUMN_TITLE))).thenReturn(event.getTitle());
        when(cursor.getString(cursor.getColumnIndexOrThrow(EventTable.COLUMN_IMAGE))).thenReturn(event.getImage());
        when(cursor.getString(cursor.getColumnIndexOrThrow(EventTable.COLUMN_LINK))).thenReturn(event.getLink());
        当(cursor.getString(cursor.getColumnIndexOrThrow(EventTable.COLUMN_RESOURCE_URI)))。thenReturn(
                        event.getResourceUri());

        //创建收益事件
        返回游标;
    }

}
 

EventsFragment.java

  @EFragment(resName =events_fragment)
公共类EventsFragment扩展SherlockFragment实现LoaderCallbacks<光标>
{
    @ViewById(R.id.events_pager)
    保护ViewPager mPager;

    @ViewById(R.id.events_indicator)
    保护CirclePageIndicator mIndicator;

    @ preF
    保护IShared prefs_米preferences;

    保护EventsFragmentAdapter pageAdapter;

    私人CursorLoader mCursorLoader;

    / **
     *初始化的CursorAdapter和光标管理器装载器。
     * /
    @AfterViews
    无效的init()
    {
        最终SherlockFragmentActivity活性= this.getSherlockActivity();

        this.pageAdapter =新EventsFragmentAdapter(activity.getSupportFragmentManager(),NULL);
        this.mPager.setAdapter(this.pageAdapter);
        this.mIndicator.setViewPager(this.mPager);
        。this.getLoaderManager()initLoader(this.mPager.getId(),null,则此);
    }

    / *(非Javadoc中)
     * @see android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader(INT,android.os.Bundle)
     * /
    @覆盖
    公共装载机<光标> onCreateLoader(最终诠释为arg0,最终捆绑ARG1)
    {
        如果(this.mCursorLoader == NULL)
        {
            //设置排序最新第一
            最后弦乐排序顺序= BaseColumns._ID +DESC; // $ NON-NLS-1 $

            this.mCursorLoader =新CursorLoader(this.getActivity(),EventContentProvider.CONTENT_URI,
                            EventTable.getProjection(),AbstractDbTable.getWhereCondition(空)
                            AbstractDbTable.getWhereArgs(this.m preferences,空),排序顺序);
        }
        返回this.mCursorLoader;
    }

    / *(非Javadoc中)
     * @看到android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished(android.support.v4.content.Loader,的java.lang.Object)
     * /
    @覆盖
    公共无效onLoadFinished(最终装载机<光标>为arg0,最后光标光标)
    {
        this.pageAdapter.swapCursor(光标);

    }

    / *(非Javadoc中)
     * @看到android.support.v4.app.LoaderManager.LoaderCallbacks#onLoaderReset(android.support.v4.content.Loader)
     * /
    @覆盖
    公共无效onLoaderReset(最终装载机<光标>为arg0)
    {
        this.pageAdapter.swapCursor(空);
    }

    / **
     *为必填仅供测试。
     *
     * @参数cursorLoader
     * /
    公共无效setCursorLoader(最终CursorLoader cursorLoader)
    {
        this.mCursorLoader = cursorLoader;
    }

    / **
     *为必填仅供测试。
     *
     * @参数cursorLoader
     * /
    公共CursorLoader getCursorLoader()
    {
        返回this.mCursorLoader;
    }

    公共布尔isCursorLoaderLoaded()
    {
        返回(this.pageAdapter.getCursor()!= NULL);
    }
}
 
Android之cursorLoader进行数据异步加载

解决方案

我不能肯定,但我敢打赌,内部code正试图用一个 的AsyncTask 执行光标加载程序的 loadInBackground()方法。您可能会看到一个僵局,因为在 的AsyncTask 试图调用 onPostExecute()。该通话将尝试在主UI线程,这恰好是你的测试程序的线程中运行。这可能永远不会发生,因为你是停留在观望与调用堆栈上的测试程序。

尝试将你的嘲讽到一个更高的水平,使没有真正发生在从测试的背景。谷歌的`AsyncTask的单元测试机器人的僵局可以看到的例子,其他人遇到了类似的问题。

Does anyone know how to test the following setup using Robolectric?

Fragment containing a ViewPager, data loaded with a CursorLoader.

With the code below, the CursorLoader is never pushed into the adapter for the view pager. I get stuck at the await() call.

EventsFragmentTest.java:

@RunWith(CustomRobolectricTestRunner.class)
public class EventsFragmentTest extends AbstractDbAndUiDriver
{
    // which element in the view pager we are testing
    private static final int           TEST_INDEX = 0;

    protected SherlockFragmentActivity mActivity;
    protected EventsFragment_          mFragment;

    @Override
    @Before
    public void setUp() throws Exception
    {
        // create activity to hold the fragment
        this.mActivity = CustomRobolectricTestRunner.getActivity();

        // create and start the fragment
        this.mFragment = new EventsFragment_();
    }

    @Test
    public void sanityTest()
    {
        // create an event
        final Event event = this.createEvent();

        // create mock cursor loader
        final Cursor cursor = this.createMockEventCursor(event);
        this.mFragment.setCursorLoader(mock(CursorLoader.class));
        when(this.mFragment.getCursorLoader().loadInBackground()).thenReturn(cursor);
        CustomRobolectricTestRunner.startFragment(this.mActivity, this.mFragment);

        await().atMost(5, SECONDS).until(this.isCursorLoaderLoaded(), equalTo(true));

        // check for data displayed
        final TextView title = this.getTextView(R.id.event_view_title);
        final TextView text = this.getTextView(R.id.event_view_text);

        // exists and visible is enough for now
        this.getImageView(R.id.event_view_image);

        assertThat(title.getText().toString(), equalTo(event.getTitle()));
        assertThat(text.getText().toString(), is(event.getText()));

        // clean up
        cursor.close();
    }

    @Override
    protected View getRootView()
    {
        return ((ViewPager) this.mFragment.getView().findViewById(R.id.events_pager)).getChildAt(TEST_INDEX);
    }

    private Callable<Boolean> isCursorLoaderLoaded()
    {
        return new Callable<Boolean>()
        {
            public Boolean call() throws Exception
            {
                return EventsFragmentTest.this.mFragment.isCursorLoaderLoaded(); // The condition that must be fulfilled
            }
        };
    }

    /**
     * Create an event
     * 
     * @return
     */
    protected Event createEvent()
    {
        // create a random event
        final Event event = new Event();
        event.setImage(null);
        event.setLink("/some/link/" + RandomUtils.getRandomString(5)); //$NON-NLS-1$
        event.setResourceUri("/rest/uri/" + RandomUtils.getRandomDouble()); //$NON-NLS-1$
        event.setText("this is a test object " + RandomUtils.getRandomString(5)); //$NON-NLS-1$
        return event;
    }

    protected Cursor createMockEventCursor(final Event event)
    {
        // Create a mock cursor.
        final Cursor cursor = new CursorWrapper(mock(MockCursor.class));

        when(cursor.getCount()).thenReturn(1);
        when(cursor.getString(cursor.getColumnIndexOrThrow(EventTable.COLUMN_TEXT))).thenReturn(event.getText());
        when(cursor.getString(cursor.getColumnIndexOrThrow(EventTable.COLUMN_TITLE))).thenReturn(event.getTitle());
        when(cursor.getString(cursor.getColumnIndexOrThrow(EventTable.COLUMN_IMAGE))).thenReturn(event.getImage());
        when(cursor.getString(cursor.getColumnIndexOrThrow(EventTable.COLUMN_LINK))).thenReturn(event.getLink());
        when(cursor.getString(cursor.getColumnIndexOrThrow(EventTable.COLUMN_RESOURCE_URI))).thenReturn(
                        event.getResourceUri());

        // return created event
        return cursor;
    }

}

EventsFragment.java

@EFragment(resName = "events_fragment")
public class EventsFragment extends SherlockFragment implements LoaderCallbacks<Cursor>
{
    @ViewById(R.id.events_pager)
    protected ViewPager             mPager;

    @ViewById(R.id.events_indicator)
    protected CirclePageIndicator   mIndicator;

    @Pref
    protected ISharedPrefs_         mPreferences;

    protected EventsFragmentAdapter pageAdapter;

    private CursorLoader            mCursorLoader;

    /**
     * initialise the cursoradapter and the cursor loader manager.
     */
    @AfterViews
    void init()
    {
        final SherlockFragmentActivity activity = this.getSherlockActivity();

        this.pageAdapter = new EventsFragmentAdapter(activity.getSupportFragmentManager(), null);
        this.mPager.setAdapter(this.pageAdapter);
        this.mIndicator.setViewPager(this.mPager);
        this.getLoaderManager().initLoader(this.mPager.getId(), null, this);
    }

    /* (non-Javadoc)
     * @see android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader(int, android.os.Bundle)
     */
    @Override
    public Loader<Cursor> onCreateLoader(final int arg0, final Bundle arg1)
    {
        if (this.mCursorLoader == null)
        {
            // set sort to newest first
            final String sortOrder = BaseColumns._ID + " DESC"; //$NON-NLS-1$

            this.mCursorLoader = new CursorLoader(this.getActivity(), EventContentProvider.CONTENT_URI,
                            EventTable.getProjection(), AbstractDbTable.getWhereCondition(null),
                            AbstractDbTable.getWhereArgs(this.mPreferences, null), sortOrder);
        }
        return this.mCursorLoader;
    }

    /* (non-Javadoc)
     * @see android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished(android.support.v4.content.Loader, java.lang.Object)
     */
    @Override
    public void onLoadFinished(final Loader<Cursor> arg0, final Cursor cursor)
    {
        this.pageAdapter.swapCursor(cursor);

    }

    /* (non-Javadoc)
     * @see android.support.v4.app.LoaderManager.LoaderCallbacks#onLoaderReset(android.support.v4.content.Loader)
     */
    @Override
    public void onLoaderReset(final Loader<Cursor> arg0)
    {
        this.pageAdapter.swapCursor(null);
    }

    /**
     * Required for testing only.
     * 
     * @param cursorLoader
     */
    public void setCursorLoader(final CursorLoader cursorLoader)
    {
        this.mCursorLoader = cursorLoader;
    }

    /**
     * Required for testing only.
     * 
     * @param cursorLoader
     */
    public CursorLoader getCursorLoader()
    {
        return this.mCursorLoader;
    }

    public boolean isCursorLoaderLoaded()
    {
        return (this.pageAdapter.getCursor() != null);
    }
}

解决方案

I'm not certain, but I would wager that the internal code is trying to use an AsyncTask to invoke the cursor loader's loadInBackground() method. You might be seeing a deadlock because the AsyncTask tries to invoke onPostExecute(). That call will try to run in your main UI thread, which happens to be the thread of your test routine. That can never happen because you are stuck in a wait with your test routine on the call stack.

Try moving your mocking up to a higher level so that nothing really happens in the background from the test. google `AsyncTask unit test android deadlock' to see examples where other people ran into similar problems.