Тестирование ViewPager (и CursorLoader) с помощью Robolectric

Кто-нибудь знает, как протестировать следующую настройку с помощью Robolectric?

Фрагмент, содержащий ViewPager, данные, загруженные CursorLoader.

С помощью приведенного ниже кода CursorLoader никогда не вставляется в адаптер для пейджера представления. Я застрял в await() вызова.

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; } } , @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; } } , @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; } } , @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; } } , @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); } } 

Solutions Collecting From Web of "Тестирование ViewPager (и CursorLoader) с помощью Robolectric"

Я не уверен, но я бы сказал, что внутренний код пытается использовать AsyncTask для вызова метода loadInBackground() загрузчика курсора. Возможно, вы видите тупик, потому что AsyncTask пытается вызвать onPostExecute() . Этот вызов попытается запустить в вашем основном потоке пользовательского интерфейса, который, случается, является нитью вашей тестовой процедуры. Это никогда не произойдет, потому что вы застряли в ожидании своей тестовой процедуры в стеке вызовов.

Попытайтесь перевести свое высмеивание на более высокий уровень, чтобы на самом деле ничего не происходило в фоновом режиме из теста. Google `AsyncTask unit test android deadlock ', чтобы увидеть примеры, когда другие люди сталкивались с подобными проблемами.