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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With