2017-06-01 55 views
0

將,我有MainActivity持有MainFragment, MainFragment實現RecipeDataFetcher回調接口,通過在RecipeDataFetcher類通過Volley /網絡獲取數據。 MainFragment有是假設顯示一對夫婦的食譜卡recyclerview如何使用Espresso測試Recycler視圖中使用抽象獲取數據的片段使用IdlingResource

-I需要在RecyclerView項目執行測試

這是我的主要fragment`public類

MainFragment extends Fragment implements RecipesRecyclerAdapter.OnRecipeItemSelected, 
     RecipesDataFetcher.RecipesFetcherDataListener { 

    private View v; 
    private RecipesDataFetcher recipesDataFetcher; 
    private OnFragmentInteractionListener mListener; 

private RecyclerView recyclerView; 
private RecipesRecyclerAdapter recipesRecyclerAdapter; 
private Recipes mRecipes; 
private RecyclerView.LayoutManager layoutManager; 


private SimpleIdlingResource mIdlingResource; 


@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, 
         Bundle savedInstanceState) { 
    v = inflater.inflate(R.layout.fragment_main, container, false); 
    mRecipes = new Recipes(); 
    recyclerView = (RecyclerView) v.findViewById(R.id.rv_recipes); 
    if (mTwoPanel) { 
     layoutManager = new GridLayoutManager(getActivity(), 2); 
    } else { 
     layoutManager = new LinearLayoutManager(getActivity()); 
    } 

    recipesRecyclerAdapter = new RecipesRecyclerAdapter(this, mRecipes); 
    recyclerView.setLayoutManager(layoutManager); 
    recyclerView.setAdapter(recipesRecyclerAdapter); 
    return v; 
} 

@VisibleForTesting 
@NonNull 
public SimpleIdlingResource getIdlingResource() { 
    if (mIdlingResource == null) { 
     mIdlingResource = new SimpleIdlingResource(); 
    } 
    return mIdlingResource; 
} 



    @Override 
    public void onSaveInstanceState(Bundle outState) { 
//  super.onSaveInstanceState(outState); 
    } 
@Override 
public void onAttach(Context context) { 
    super.onAttach(context); 
    if (context instanceof OnFragmentInteractionListener) { 
     mListener = (OnFragmentInteractionListener) context; 
    } else { 
     throw new RuntimeException(context.toString() 
       + " must implement OnFragmentInteractionListener"); 
    } 
} 

@Override 
public void onDetach() { 
    super.onDetach(); 
    mListener = null; 
} 

@Override 
public void onItemSelected(int itemPosition) { 
    mListener.onFragmentInteraction(mRecipes.get(itemPosition), mRecipes.size()); 
} 

@Override 
public void onResume() { 
    super.onResume(); 
    if (mRecipes.isEmpty()) { 
     getData(); 
    } 
} 

@Override 
public void onConnectionFailure() { 
    if (!checkOnlineState(getActivity())) { 
     Logging.shortToast(getActivity(), getString(R.string.internet_error)); 
    } else { 
     Logging.shortToast(getActivity(), getString(R.string.server_error)); 
    } 
} 

private void getData() { 
    recipesDataFetcher = new RecipesDataFetcher(getActivity(), this); 
    recipesDataFetcher.getRecipes(mIdlingResource); 
} 

@Override 
public void onConnectionDone(Recipes recipes) { 

    mRecipes.addAll(recipes); 
    recipesRecyclerAdapter.notifyDataSetChanged(); 

    //TODO: Do bulk inset in a background thread and for once 
    ContentValues[] contentValues = new ContentValues[recipes.size()]; 
    for (int i = 0; i < recipes.size(); i++) { 
     ContentValues contentValue = new ContentValues(); 
     Gson gson = new Gson(); 
     String ingredients = gson.toJson(recipes.get(i).getIngredients()); 
     String steps = gson.toJson(recipes.get(i).getSteps()); 
     contentValue.put(COLUMN_RECIPE_INGREDIENTS, ingredients); 
     contentValue.put(COLUMN_RECIPE_STEPS, steps); 
     contentValue.put(COLUMN_RECIPE_SERVINGS, recipes.get(i).getServings()); 
     contentValue.put(COLUMN_RECIPE_IMAGE, recipes.get(i).getImage()); 
     contentValue.put(COLUMN_RECIPE_NAME, recipes.get(i).getName()); 
     contentValues[i] = contentValue; 
    } 

    getContext().getContentResolver().bulkInsert(CONTENT_URI, contentValues); 

    if(mIdlingResource!=null){ 
     mIdlingResource.setIdleState(true); 
    } 

} 


public interface OnFragmentInteractionListener { 
    void onFragmentInteraction(Recipe recipe, int size); 
}` 

這裏是我dataFetching類

public class RecipesDataFetcher extends BaseDataFetcher { 
    public RecipesDataFetcher(Context context, BaseDataFetcherListener mListener) { 
     super(context, mListener); 
    } 



    public void getRecipes(SimpleIdlingResource simpleIdlingResource) { 
      if(simpleIdlingResource!=null){ 
      simpleIdlingResource.setIdleState(false);} 
     String URL = BaseURL; 
    Logging.log("getCountries: " + URL); 
    JsonArrayRequest jsonObjReq = new JsonArrayRequest(URL, (JSONArray jsonArr) -> { 
     Logging.log("getCountries response: " + jsonArr.toString()); 
     Recipes recipes = new Recipes(jsonArr); 
     ((RecipesFetcherDataListener) mListener).onConnectionDone(recipes); 
     if(simpleIdlingResource!=null){ 
      simpleIdlingResource.setIdleState(true); 
     } 
    }, this.errorListener); 
    retryPolicy(jsonObjReq); 
    getReQ().add(jsonObjReq); 
} 

public interface RecipesFetcherDataListener extends BaseDataFetcherListener { 
    void onConnectionDone(Recipes recipes); 
} 

}

的下面是我的測試類

@RunWith(AndroidJUnit4.class) 
    public class MyFragmentTest { 

     private SimpleIdlingResource mIdlingResource; 

    @Rule 
    public FragmentTestRule<MainFragment> mFragmentTestRule = new FragmentTestRule<>(MainFragment.class); 

    @Before 
    public void registerIdlingResource() { 
     // Launch the activity to make the fragment visible 
     mFragmentTestRule.launchActivity(null); 
     mIdlingResource = mFragmentTestRule.getFragment().getIdlingResource(); 
     Espresso.registerIdlingResources(mIdlingResource); 
    } 

    @Test 
    public void fragment_can_be_instantiated() { 


     // Then to test item in position 0 
     onView(withId(R.id.rv_recipes)) 
       .perform(RecyclerViewActions.actionOnItemAtPosition(0, click())); 
    } 

    // unregister resources 
    @After 
    public void unregisterIdlingResource() { 
     if (mIdlingResource != null) { 
      Espresso.unregisterIdlingResources(mIdlingResource); 
     } 
    } 
} 

最後here是整個代碼項目,只是讓我知道我在做什麼錯了究竟:d,您的幫助將得到高度讚賞。

+0

可以提醒你所面對的問題!? – Ibrahim

+0

@IbrahimAli你提到這個問題是什麼意思? :/ –

回答

0

解釋爲錯誤

具有資源庫參觀,並運行MyFragmentTest測試類

後,我面臨兩個錯誤它們

  1. 的java.lang .RuntimeException:[email protected]必須實現OnFragmentInteractionListener

這是因爲在FragmentTestRule類你伸出ActivityTestRule < 測試活動>其中測試活動沒有實現OnFragmentInteractionListener所以解決的辦法是,你必須擴展MainActivity它已經實現了這個接口,所以這類應該是這樣的:

public class FragmentTestRule<F extends Fragment> extends ActivityTestRule<MainActivity> { 

private final Class<F> mFragmentClass; 
private F mFragment; 

public FragmentTestRule(final Class<F> fragmentClass) { 
    super(MainActivity.class, true, false); 
    mFragmentClass = fragmentClass; 
} 
..... 
  • java.la ng.NullPointerException:嘗試調用虛擬方法「com.baking.www.baking.IdlingResource.SimpleIdlingResource com.baking.www.baking.fragments.MainFragment.getIdlingResource()」上的空對象引用
  • 發生這種情況因爲在你的MyFragmentTest 註釋什麼開始前@Before被稱爲導致你的片段尚未創建,使這條線沒有意義

    mIdlingResource = mFragmentTestRule.getFragment().getIdlingResource(); 
    

    所以我的觀點: 做不使用碎片。活動更容易測試。您可以自行測試每個活動。在大多數情況下,碎片對活動沒有任何優勢。片段只是使實施和測試更加困難。

    替代解決方案與運行凌空怠速資源

    (一)MainActivity.java

    添加這些行

    @Nullable 
    public SimpleIdlingResource mIdlingResource; 
    
    @VisibleForTesting 
    @NonNull 
    public SimpleIdlingResource getIdlingResource() { 
        if (mIdlingResource == null) { 
         mIdlingResource = new SimpleIdlingResource(); 
        } 
        return mIdlingResource; 
    } 
    

    ,並在您的onCreate調用此方法 getIdling資源(); 從idlingResouce獲取實例。

    (二)MainFragment.java

    • 刪除類變量mIdlingResource,它的getMethod
    • 你會發現錯誤,爲mIdlingResource
    • 中的((MainActivity更換任何mIdlingResource )getActivity())。mIdlingResource

    (c)和最後這是新MainActivityTest

    @RunWith(AndroidJUnit4.class) 
    public class MainActivityTest { 
    
    @Rule 
    public ActivityTestRule<MainActivity> mActivityTestRule = 
         new ActivityTestRule<>(MainActivity.class); 
    
    private IdlingResource mIdlingResource; 
    
    
    // Registers any resource that needs to be synchronized with Espresso before the test is run. 
    @Before 
    public void registerIdlingResource() { 
        mIdlingResource = mActivityTestRule.getActivity().getIdlingResource(); 
        // To prove that the test fails, omit this call: 
        Espresso.registerIdlingResources(mIdlingResource); 
    } 
    
    @Test 
    public void idlingResourceTest() { 
        onView(withId(R.id.rv_recipes)).check(matches(isDisplayed())); 
        onView(withId(R.id.rv_recipes)) 
          .perform(RecyclerViewActions.actionOnItemAtPosition(0, click())); 
    } 
    
    // Remember to unregister resources when not needed to avoid malfunction. 
    @After 
    public void unregisterIdlingResource() { 
        if (mIdlingResource != null) { 
         Espresso.unregisterIdlingResources(mIdlingResource); 
        } 
    } 
    
    } 
    

    很抱歉的長期答案希望我幫助:) :)

    相關問題