Android Unit Test cases for RecyclerView in Fragment

Viewed 651

I'm trying to write test for the recyclerview in fragment but always seems to be stucks with same error (androidx.test.espresso.NoMatchingRootException) no matter which solution I try.

Error

androidx.test.espresso.NoMatchingRootException: Matcher 'with decor view is <DecorView@814c399[]>' did not match any of the following roots: [Root{application-window-token=android.view.ViewRootImpl$W@5c6165e, window-token=android.view.ViewRootImpl$W@5c6165e, has-window-focus=false, layout-params-type=1, layout-params-string={(0,0)(fillxfill) sim={adjust=pan} ty=BASE_APPLICATION wanim=0x10302fe
  fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
  pfl=FORCE_DRAW_STATUS_BAR_BACKGROUND}, decor-view-string=DecorView{id=-1, visibility=VISIBLE, width=1080, height=2280, has-focus=true, has-focusable=true, has-window-focus=false, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params={(0,0)(fillxfill) sim={adjust=pan} ty=BASE_APPLICATION wanim=0x10302fe
  fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
  pfl=FORCE_DRAW_STATUS_BAR_BACKGROUND}, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=3}}]

ListTestFragment.java

public class ListTestFragment {
    private ListTestFragment fragment;

    @Rule
    public ActivityTestRule<BottomNavigationActivity> activityActivityTestRule = new ActivityTestRule<BottomNavigationActivity>(BottomNavigationActivity.class);

    @Before
    public void setUp() {
        activityActivityTestRule.getActivity().getSupportFragmentManager().beginTransaction();
        activityActivityTestRule.getActivity().openChatFragment(null);
        fragment = activityActivityTestRule.getActivity().chatFragment;
    }

    @BeforeClass
    public static void testClassSetup() {
        System.out.println("Getting test class ready");
    }

    @AfterClass
    public static void testClassCleanup() {
        System.out.println("Done with tests");
    }

    @After
    public void cleanup() {
        System.out.println("Done with unit test!");
    }


    @Test
    public void testSampleRecyclerVisible() {
        Espresso.onView((withId(R.id.container)))
                .inRoot(RootMatchers.withDecorView(
                        Matchers.is(activityActivityTestRule.getActivity().getWindow().getDecorView())))
                .check(matches(isDisplayed()));
    }

    @Test
    public void testCaseForRecyclerClick() {
        Espresso.onView(ViewMatchers.withId(R.id.recyclerview))
                .inRoot(RootMatchers.withDecorView(
                        Matchers.is(activityActivityTestRule.getActivity().getWindow().getDecorView())))
                .perform(RecyclerViewActions.actionOnItemAtPosition(0, click()));
    }

    @Test
    public void testCaseForRecyclerScroll() {
        // Get total item of RecyclerView
        RecyclerView recyclerView = activityActivityTestRule.getActivity().findViewById(R.id.recyclerview);
        int itemCount = 20;

        // Scroll to end of page with position
        Espresso.onView(ViewMatchers.withId(R.id.recyclerview))
                .inRoot(RootMatchers.withDecorView(
                        Matchers.is(activityActivityTestRule.getActivity().getWindow().getDecorView())))
                .perform(RecyclerViewActions.scrollToPosition(itemCount - 1));
    }
}

openChatFragment() method

public void openChatFragment(CloseDialogFragmentInterface closeDialogFragmentInterface) {
        chatFragment = new ChatListFragment();
        Utils.openFragment(this, chatFragment, false, tasksTitle + "Fragment");
    }

openFragment() method

public static void openFragment(AppCompatActivity appCompatActivity, Fragment fragment, boolean addTobackStack, String tag) {
    try {

        FragmentManager fm = appCompatActivity.getSupportFragmentManager();
        String fragmentName = fragment.getClass().getSimpleName();
        fm.popBackStack(fragmentName, FragmentManager.POP_BACK_STACK_INCLUSIVE);

        FragmentManager fragmentManager = appCompatActivity.getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        if (addTobackStack) {
            fragmentTransaction.addToBackStack(fragmentName);
        }
        fragmentTransaction.replace(R.id.container, fragment, tag);
        fragmentTransaction.commit();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

I believe it's related to finding the id of recyclerview, just can't figure out the correct way to do so. Any help is appreciated. Thanks

2 Answers

If you are testing the UI that is in fragment, then you can you inbuilt methods of fragment testing of espresso.

Dependency for fragment testing with espresso

dependencies {
    def fragment_version = "1.3.6"

    debugImplementation "androidx.fragment:fragment-testing:$fragment_version"
}

To launch fragment, write following code in your setup method

val scenario = launchFragmentInContainer<EventFragment>(fragmentArgs)

You can get more info regarding fragment testing in espresso here

Use the Barista library for UI tests, it is the easiest solution and makes everything easier. https://github.com/AdevintaSpain/Barista

Inside it, try to use RecyclerView testing methods:

clickListItem(R.id.list, 4);
clickListItemChild(R.id.list, 3, R.id.row_button);
scrollListToPosition(R.id.list, 4);

assertDisplayedAtPosition(R.id.list, 0, "text");
assertDisplayedAtPosition(R.id.list, 0, R.id.text_field, "text");
assertDisplayedAtPosition(R.id.list, 0, R.string.hello_world);
assertDisplayedAtPosition(R.id.list, 0, R.id.text_field, 
R.string.hello_world);
assertDrawableDisplayedAtPosition(R.id.recycler, 0, R.id.imageview, 
R.drawable.ic_barista);
Related