2017-06-01 53 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); 
        } 
    } 
    
    } 
    

    很抱歉的长期答案希望我帮助:) :)

    相关问题