2017-06-01 2 views
0

aura, MainActivity qui détient MainFragment, MainFragment implémente une interface de rappel RecipeDataFetcher qui apporte des données reçues par Volley/réseau dans RecipeDataFetcher Class. MainFragment a une recyclerview qui est supposé afficher quelques recettes cartesComment utiliser les tests Espresso Recycler voir dans un fragment obtenir des données avec volley en utilisant IdlingResource

-I besoin d'exécuter un test sur un article RecyclerView

Voici ma classe principale 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); 
}` 

et ici est ma classe 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); 
} 

}

Une

Voici mon test classe

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

Enfin here est l'ensemble du projet de code, juste faites-moi savoir ce que je fais mal exactement: D, votre aide serait très appréciée.

+0

peut vous rappeler la question que vous fait face! – Ibrahim

+0

@IbrahimAli que voulez-vous dire en rappelant le problème? : / –

Répondre

0

Explication pour les erreurs

Après avoir une visite à votre dépôt et exécutez le MyFragmentTest test classe

i face à deux erreurs qui sont

  1. java.lang .RuntimeException: [email protected] doit implémenter OnFragmentInteractionListener

Cela se produit parce que dans le FragmentTestRule classe vous Prolonge ActivityTestRule < TestActivity> où TestActivity pas mis en œuvre OnFragmentInteractionListener de sorte que la solution est que vous devez étend MainActivity qui mettent déjà en oeuvre cette interface si cette classe devrait être ressembler à ceci:

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; 
} 
..... 
  1. java.la ng.NullPointerException: tentative d'invoquer la méthode virtuelle 'com.baking.www.baking.IdlingResource.SimpleIdlingResource com.baking.www.baking.fragments.MainFragment.getIdlingResource()' sur une référence d'objet null

Cela se produit parce que dans votre MyFragmentTest l'annotation @Before est appelé avant tout a commencé ce qui conduit à ce que votre fragment n'a pas encore créé cette ligne qui font pas de sens

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

donc, à mon point de vue: Faire n'utilisez pas de Fragments. Les activités sont plus faciles à tester. Vous pouvez tester chaque activité par elle-même. Dans la plupart des cas, les fragments n'offrent aucun avantage sur les activités.Les fragments rendent l'implémentation et les tests plus difficiles.

Solution alternative pour exécuter les ressources avec la marche au ralenti volley

(a) MainActivity.java

ajouter ces lignes

@Nullable 
public SimpleIdlingResource mIdlingResource; 

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

et dans votre onCreate appeler cette méthode getIdling Ressource(); pour prendre l'instance de idlingResouce.

(b) dans MainFragment.java

  • enlever la variable de classe mIdlingResource et il est getMethod
  • vous trouverez des erreurs pour mIdlingResource
  • remplacer tout mIdlingResource avec ((MainActivity) getActivity()). mIdlingResource

(c) et enfin c'est le nouveau 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); 
    } 
} 

} 

Désolé pour la longue espérance de réponse j'ai aidé :) :)