2013-07-05 10 views
7
के साथ एक CursorLoader परीक्षण

को देखते हुए मैं एक साधारण ListFragment विकासशील कर रहा हूँ इस तरह (इस मामले में, यह Mediastore से कलाकारों की एक सूची पढ़ता है, लेकिन यह भी बाद में एक अलग स्रोत से डेटा पढ़ा जाएगा):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); 
    } 
} 

मैं सबूत टुकड़ा विभिन्न स्थितियों पर ठीक से बर्ताव करता है (उदाहरण के लिए खाली सूची या अमान्य डेटा आदि) के लिए Robolectric + Mockito + awaitility उपयोग करना चाहते हैं। मेरा परीक्षण वर्ग इस तरह दिखता है: जब इंटेलीजे में इस परीक्षण चल रहे हैं या maven परीक्षण असफल हो जायेगी तब

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

, अनुकूलक हमेशा शून्य की गिनती वापस आ जाएगी।

ऑनरेट लोडर में System.out.println कथन हालांकि देता है। क्या मुझे पृष्ठभूमि थ्रेड में मॉकिटो के लिए विशेष देखभाल करने की आवश्यकता है? (loadInBackground विधि एक कार्यकर्ता थ्रेड पर चलता है)।

उत्तर

1

समाधान का उपयोग करने के लिए है।

+0

क्या आप मुझे पूरा यूनिट टेस्ट क्लास दे सकते हैं? मुझे भी एक ही समस्या का सामना करना पड़ रहा है और उसी कर्सरलोडर का उपयोग कर रहा हूं। – user2566484

1

मुझे अभी लोडर परीक्षण मेरे कोड में काम कर चुके हैं। मेरे मामले में मुझे फ्रैगमेंट कोड के माध्यम से इसे रूट करने की कोशिश करने के बजाय लोडर का परीक्षण करने के लिए और अधिक प्रत्यक्ष पाया गया।

मैं इस पोस्ट से कोड का एक थोड़ा संशोधित संस्करण का उपयोग कर को समाप्त: https://groups.google.com/forum/#!msg/robolectric/xY5MF399jA8/V5PnUfh1D-wJ

पहले, मैं कुछ छाया वर्गों को लागू करने के लिए किया था क्योंकि Robolectric2 AsyncTaskLoader या लोडर कक्षाओं के लिए छाया कोड शामिल नहीं है। यदि आपने कभी शैडो क्लास को नहीं जोड़ा है, तो यह जानना महत्वपूर्ण है कि आप इन्हें सही पैकेज में डाल दें। इन दोनों छायाओं को औरroid.support.v4.content में रहना चाहिए।

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

फिर, अपने कॉन्फ़िगरेशन के आधार पर आप एक एनोटेशन इस बिंदु बुला loader.onStartLoading पर कस्टम कक्षाओं

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

उपयोग करने के लिए जोड़ सकते हैं() लोडर को किसी भी प्रतीक्षा कॉम को हैक किए बिना अपेक्षित के रूप में चलाने का कारण बनता है मेरे परीक्षण मामलों में बैंड।

उम्मीद है कि इससे मदद मिलती है। मैंने लोडरमैनेजर का परीक्षण करने की इस विधि के साथ प्रयोग करने की कोशिश नहीं की है, इसलिए मैं यह सत्यापित नहीं कर सकता कि यह उस कॉल के माध्यम से काम करता है।

नोट: कारण मैंने छायालोडर जोड़ा है क्योंकि मुझे लगता है कि रीसेट() जब मैं इसकी अपेक्षा नहीं कर रहा था तो सच हो रहा था।

Robolectric.flushForegroundThreadScheduler(); 

(Robolectric 3.0)

यह CursorLoader सहित, तुरंत सभी कार्य चलेंगे:

+0

दुर्भाग्य से मेरे लिए काम नहीं करता है। – rumpel