Testing a CursorLoader with Robolectric & Mockito
android, mockito, robolectric
Solution
The solution is to use:
Robolectric.flushForegroundThreadScheduler();
(Robolectric 3.0)
This will run all tasks immediately, including the CursorLoader.
Problem
Given I'm developing a simple ListFragment (in this case, it reads a list of Artists from the MediaStore, but will also read data from a different source later) like this: ``` @EFragment public class ArtistsFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor> { private static final String TAG = ArtistsFragment.class.getName(); private SimpleCursorAdapter mAdapter; Uri uri = MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI; CursorLoader mCursorLoader; @AfterViews void setupView() { mAdapter = new SimpleCursorAdapter(getActivity(), android.R.layout.simple_list_item_1, null, new String[]{MediaStore.Audio.Artists.ARTIST}, // lists path of files new int[]{android.R.id.text1}, 0); setListAdapter(mAdapter); getLoaderManager().initLoader(0, null, this); } @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { if (mCursorLoader == null) { mCursorLoader = new CursorLoader(getActivity(), uri, new String[]{MediaStore.Audio.Artists._ID, MediaStore.Audio.Artists.ARTIST}, null, null, MediaStore.Audio.Artists.ARTIST + " ASC"); } else { System.out.println("mCursorLoader.count: " + mCursorLoader.loadInBackground().getCount()); } return mCursorLoader; } @Override public void onLoadFinished(Loader<Cursor> loader, Cursor data) { setListShown(true); mAdapter.swapCursor(data); } @Override public void onLoaderReset(Loader<Cursor> loader) { mAdapter.swapCursor(null); } } ``` I want to use Robolectric + Mockito + awaitility to proof the Fragment behaves properly on various conditions (e.g. empty list or invalid data etc). My test class looks like this: ``` @RunWith(RobolectricTestRunner.class) public class ArtistsFragmentTest { @Test public void shouldNotBeNull() { final ArtistsFragment myFragment = ArtistsFragment_.builder().build(); assertNotNull(myFragment); // Create a mock cursor. final Cursor mc = getSampleArtistCursor(); when(mc.getCount()).thenReturn(1); when(mc.getInt(0)).thenReturn(1); when(mc.getString(1)).thenReturn("Sample Title"); myFragment.mCursorLoader = mock(CursorLoader.class); when(myFragment.mCursorLoader.loadInBackground()).thenReturn(mc); startFragment(myFragment); assertNotNull(myFragment.getListView()); await().atMost(5, TimeUnit.SECONDS).until(new Callable<Integer>() { @Override public Integer call() throws Exception { return myFragment.getListAdapter().getCount(); } }, equalTo(1)); System.out.println(myFragment.getListAdapter().getCount()); } private Cursor getSampleArtistCursor() { return new CursorWrapper(mock(MockCursor.class)); } } ``` Then when running this test in IntelliJ or maven the test will fail, the adapter will always return a count of zero. The System.out.println statement in onCreateLoader however returns 1. Do I need to take special care for Mockito in background threads? (the loadInBackground method runs on a worker thread).