ViewPager'ı (ve CursorLoader) Robolectric ile Test Etme


91

Robolectric kullanarak aşağıdaki kurulumun nasıl test edileceğini bilen var mı?

Bir ViewPager içeren parça, CursorLoader ile yüklenen veriler.

Aşağıdaki kodla, CursorLoader hiçbir zaman görüntüleme çağrı cihazı için adaptörün içine itilmez. await()Aramaya takılı kaldım .

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
Görünüşe göre Birim testi yerine bir Sistem Testi yazmaya çalışıyorsunuz, bu doğru bir varsayım mı? Eğer öyleyse, bu Robotium veya Espresso ile çok daha kolay yapılabilir. Robolectric, Android'e özgü referansları olan ancak kullanıcının ne göreceğini test etmeyen birim veya entegrasyon testleri yazmaya çalışırken gerçekten yararlıdır.
Elliott

Biraz konuşmayı özledim, Robolectric kullanıcının gördüklerini test etmenize yardımcı olmaya çalışıyor. Karşılaşacağınızı düşündüğüm sorun, üretimde doğru kod yolunu muhtemelen test etmeyecek çok fazla önyükleme bağlama kodu yazmak zorunda olmanız ve zamanlı beklemeleri kullanmaya çalışmak genellikle testi kırılgan hale getiriyor çünkü uzun zaman uyumsuz görevler sürecektir.
Elliott

Hızlı testler almaya çalışıyorum. Robotium'da testler yazabilirim ve sıklıkla yazabilirim, ancak bunlar Robolectric'ten önemli ölçüde daha yavaştır. Benim için ideal bir dünya, 2 set testin kurulumu, desteği ve bakımı olmamasıdır. Buradaki amacım buydu.
Corey Scott

1
Sadece bir düşünce, Robolectric.runBackgroundTasks();herhangi bir iyi - muhtemelen yerineawait
weston

1
@Elliott'a katılıyorum, birim testleri gibi entegrasyon testleri veya senaryo testleri oluşturmaya çalışıyorsunuz ve bunun anlamı bu değil, robolectric cezasını kesmek / kötüye kullanmak istiyorsanız, ancak bir bedeli var. robolectric, sınıfları değil, yalnızca saplamalar sağlar.
codeScriber

Yanıtlar:


1

Emin değilim, ancak dahili kodun AsyncTaskimleç yükleyicinin loadInBackground()yöntemini çağırmak için bir kullanmaya çalıştığına bahse girerim . Çağırmaya AsyncTaskçalıştığı için bir çıkmaz görüyor olabilirsiniz onPostExecute(). Bu çağrı, test rutininizin iş parçacığı olan ana UI iş parçacığınızda çalışmayı deneyecektir. Bu asla gerçekleşemez çünkü çağrı yığınındaki test rutininizle beklemede kalırsınız.

Alayınızı daha yüksek bir seviyeye taşımayı deneyin, böylece testten arka planda gerçekten hiçbir şey olmaz. başkalarının benzer sorunlarla karşılaştığı örnekleri görmek için google `` AsyncTask unit test android deadlock '' .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.