91

Кто-нибудь знает, как протестировать следующую настройку с помощью Robolectric?Тестирование ViewPager (и CursorLoader) с помощью 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; 
    } 

} 

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); 
    } 
} 
+6

Похоже, вы пытаетесь написать больше системного теста, а не блока, это правильное предположение? Если так, то это может быть сделано намного проще с Robotium или Espresso. Robolectric действительно полезен, когда вы пытаетесь написать тесты на единицу или интеграцию, которые имеют специфические для Android ссылки, но не проверяют, что увидит пользователь. – Elliott

+0

Я пропустил немного поговорить, Robolectric пытается помочь вам проверить, что видит пользователь. Проблема, о которой я думаю, что вы собираетесь столкнуться, заключается в том, что вам приходится писать слишком большой код привязки к загрузке, который, возможно, не проверяет правильный код в процессе производства и пытается использовать ожидаемые ожидания, как правило, делает тест хрупким, потому что не известно, как потребуются длинные асинхронные задачи. – Elliott

+0

Я пытаюсь получить быстрые тесты. Я могу и часто пишу тесты в Robotium, но они значительно медленнее, чем Robolectric. Идеальный мир для меня не будет иметь установки, поддержки и поддержки двух наборов тестов. Это было мое намерение здесь. –

ответ

1

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

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

Смежные вопросы