ITKeyword,专注技术干货聚合推荐

注册 | 登录

android - Testing ViewPager (and CursorLoader) with Robolectric

itPublisher 分享于

2021腾讯云限时秒杀,爆款1核2G云服务器298元/3年!(领取2860元代金券),
地址https://cloud.tencent.com/act/cps/redirect?redirect=1062

2021阿里云最低价产品入口+领取代金券(老用户3折起),
入口地址https://www.aliyun.com/minisite/goods

推荐:android CursorLoader用法介绍

原文:  http://www.jb51.net/article/37767.htm http://write.blog.csdn.net/posteditref=toolbar android CursorLoader用法介绍 工作内容集中到Contact模块

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

推荐:深入源码解析Android中Loader、AsyncTaskLoader、CursorLoader、LoaderManager

如果对Loader、AsyncTaskLoader、CursorLoader、LoaderManager等概念不明白或不知道如何使用Loader机制,可参见博文Android中Loader及LoaderManager的使用(附源

@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);
    }
}
android robolectric android-testing android-cursorloader
|
  this question
edited Apr 26 '15 at 5:56 Avadhani Y 5,580 13 43 79 asked Dec 3 '13 at 8:47 Corey Scott 1,729 3 17 31 6   It looks like you are trying to write more of a System Test rather than a Unit test, is that a correct assumption? If so this could be done much easier with Robotium or Espresso. Robolectric is really helpful when you are trying to write unit or integration tests that have Android specific references but are not testing what the user will see. –  Elliott Jul 23 '14 at 15:46      I miss spoke slightly, Robolectric is trying to help you test what the user is seeing. The issue I think you are going to run into is that you are having to write too much boot strapping code that won't possibly test the correct code path in production and trying to use timed waits generally makes test brittle because there is no telling how long async tasks will take. –  Elliott Jul 23 '14 at 15:58      I am trying to get fast tests. I can and often do write tests in Robotium but they are significantly slower to run than Robolectric. An ideal world for me would be not having setup, support and maintain 2 sets of tests. This was my intent here. –  Corey Scott Jul 24 '14 at 9:07 1   Just a thought, Robolectric.runBackgroundTasks(); any good - probably instead of the await –  weston Feb 20 '15 at 9:28 1   i agree with @Elliott you are trying to create integration tests or scenario tests like unit tests and it's not what it meant for, if u want to hack\abuse robolectric fine, but there is a price. robolectric provides stubs only, not classes. –  codeScriber Jun 28 '15 at 16:57  |  show more comment

1 Answers
1

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.


|
  this answer
edited Jul 27 '15 at 14:08 Sdghasemi 353 4 13 answered Jul 23 '15 at 19:39 bigh_29 600 6 12

 | 

推荐:Android Loader(三) 结合CursorLoader分析Loader相关源码

Android Loader(二) CursorLoader Android Loader(四) 自定义Loader从网络中获取文本数据 首先从加载数据的过程开始分析。 初始化Loader的方法是:getLoaderMana


相关阅读排行


相关内容推荐

最新文章

×

×

请激活账号

为了能正常使用评论、编辑功能及以后陆续为用户提供的其他产品,请激活账号。

您的注册邮箱: 修改

重新发送激活邮件 进入我的邮箱

如果您没有收到激活邮件,请注意检查垃圾箱。