2013-07-05 28 views
7
ile CursorLoader test

böyle basit bir ListFragment geliştiriyorum Verilen (bu durumda, bu Mediastore gelen Sanatçıların bir listesini okur, aynı zamanda daha sonra farklı bir kaynaktan gelen verileri okuyacak):Robolectric & Mockito

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

Ben Fragment çeşitli koşullara uygun şekilde davranır ispat (örn boş liste veya geçersiz veri vs) için Robolectric + Mockito + awaitility kullanmak istiyorum. Benim test sınıf şuna benzer:

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

Sonra IntelliJ bu testi çalıştıran veya test başarısız olur maven zaman, adaptör hep sıfır sayısını döndürür.

onCreateLoader'daki System.out.println ifadesi, 'u döndürür. background thread içinde Mockito'ya özel dikkat göstermem gerekiyor mu? (loadInBackground yöntemi bir çalışan iş parçacığı üzerinde çalışır).

cevap

1

çözeltisi kullanmaktır.

+0

Çalışan Birim test sınıfını tamamlamanızı sağlayabilir misiniz? Aynı problemle karşılaşıyorum ve aynı imleç kullanıyorum. – user2566484

1

Sadece benim kodunda çalışan Yükleyici testleri aldık. Benim durumumda, Fragman kodu üzerinden yönlendirmeyi denemek yerine, yükleyiciyi test etmek için daha doğrudan buldum.

ben bu yazı kod biraz değiştirilmiş bir sürümünü kullanarak sarılır: https://groups.google.com/forum/#!msg/robolectric/xY5MF399jA8/V5PnUfh1D-wJ

Birincisi, Robolectric2 AsyncTaskLoader veya Yükleyici sınıfları için gölge kodunu içermiyorsa çünkü bazı gölge sınıfları uygulamak zorunda kaldı. Hiç bir gölge sınıfı eklemediyseniz, bunları doğru pakete koymanızın önemli olduğunu bilin. Bu gölgelerin ikisi de android.support.v4.content'da yaşamalıdır.

ShadowLoader

@Implements(Loader.class) 
public class ShadowLoader<D> { 

// ////////////////////// 
// Constants 

// ////////////////////// 
// Fields 
protected boolean reset; 

// ////////////////////// 
// Constructors 

// ////////////////////// 
// Getter & Setter 

// ////////////////////// 
// Methods from SuperClass/Interfaces 

@Implementation 
public void reset() { 
    reset = true; 
} 

@Implementation 
public boolean isReset() { 
    return reset; 
} 
// ////////////////////// 
// Methods 

// ////////////////////// 
// Inner and Anonymous Classes 
} 

ShadowAsyncTaskLoader

@Implements(AsyncTaskLoader.class) 
public class ShadowAsyncTaskLoader<D> extends ShadowLoader { 

@RealObject 
private AsyncTaskLoader<D> asyncTaskLoader; 

@Implementation 
void executePendingTask() { 
    new AsyncTask<Void, Void, D>() { 
     @Override 
     protected D doInBackground(Void... params) { 
      return (D) asyncTaskLoader.loadInBackground(); 
     } 

     @Override 
     protected void onPostExecute(D data) { 
      updateLastLoadCompleteTimeField(); 
      asyncTaskLoader.deliverResult(data); 
     } 

     @Override 
     protected void onCancelled(D data) { 
      updateLastLoadCompleteTimeField(); 
      asyncTaskLoader.onCanceled(data); 

      executePendingTask(); 
     } 
    }.execute((Void)null); 
} 


public void setReset(boolean reset) { 
    this.reset = reset; 
} 

private void updateLastLoadCompleteTimeField() { 
    try { 
     Field mLastLoadCompleteTimeField = AsyncTaskLoader.class.getDeclaredField("mLastLoadCompleteTime"); 
     if(!mLastLoadCompleteTimeField.isAccessible()) { 
      mLastLoadCompleteTimeField.setAccessible(true); 
     } 
     mLastLoadCompleteTimeField.set(asyncTaskLoader, SystemClock.uptimeMillis()); 

    } catch(NoSuchFieldException e) { 
     e.printStackTrace(); 
    } catch(IllegalAccessException e) { 
     e.printStackTrace(); 
    } 
} 
} 

Ardından, yapılandırmaya bağlı olarak bu nokta çağıran loader.onStartLoading anda özel sınıflar

@Config(shadows = { ShadowAsyncTaskLoader.class, ShadowLoader.class}) 

kullanmak için bir ek açıklama ekleyebilir() yükleyicinin beklemeden beklemek zorunda kalmadan beklendiği gibi çalışmasına neden oldu Test vakalarımı mands.

Bu yardımcı olur umarım. LoaderManager'ı bu test yöntemiyle kullanmayı denemedim, bu yüzden bu aramada çalıştığını doğrulayamıyorum.

Not: ShadowLoader eklediğim nedeni, onu beklemediğim zaman isReset() öğesinin doğru olduğunu bulmasıydı.

Robolectric.flushForegroundThreadScheduler(); 

(Robolectric 3.0)

Bu CursorLoader de dahil olmak üzere, hemen tüm görevleri çalışır:

+0

Maalesef benim için çalışmıyor. – rumpel