Assert proper number of items in list with espresso
Asked Answered
C

3

9

What is the best way to inspect and assert that a listview is the expected size with android espresso?

I wrote this matcher, but don't quite know how to integrate it into the test.

public static Matcher<View> withListSize (final int size) {
    return new TypeSafeMatcher<View> () {
        @Override public boolean matchesSafely (final View view) {
            return ((ListView) view).getChildCount () == size;
        }

        @Override public void describeTo (final Description description) {
            description.appendText ("ListView should have " + size + " items");
        }
    };
}
Chamblee answered 20/5, 2015 at 21:55 Comment(1)
If the espresso is good, things in a list don't matter. Now going for one.Zeniazenith
C
30

Figured this out.

class Matchers {
  public static Matcher<View> withListSize (final int size) {
    return new TypeSafeMatcher<View> () {
      @Override public boolean matchesSafely (final View view) {
        return ((ListView) view).getCount () == size;
      }

      @Override public void describeTo (final Description description) {
        description.appendText ("ListView should have " + size + " items");
      }
    };
  }
}

If expecting one item in the list, put this in the actual test script.

onView (withId (android.R.id.list)).check (ViewAssertions.matches (Matchers.withListSize (1)));
Chamblee answered 20/5, 2015 at 22:19 Comment(3)
I can't seem to find the method Matchers.withListSize(1) ... can you please tell me the whole classpath and perhaps the relevant version of the Matchers?Sherellsherer
The method is in the question and was written by me. Put it in your own Matchers class. I've added it into the answer now. You may need to make the class public depending on where you put it in relation to your espresso test script.Chamblee
Just calling getChildCount() is only going to give you the number of children currently attached to the view, not the total number of items in the adapter.Circumgyration
V
9

There are two different approaches of getting items count in a list with espresso: First one is as @CoryRoy mentioned above - using TypeSafeMatcher, the other one is to use BoundedMatcher.

And because @CoryRoy already showed how to assert it, here I'd like to tell how to get(return) the number using different matchers.

public class CountHelper {

    private static int count;

    public static int getCountFromListUsingTypeSafeMatcher(@IdRes int listViewId) {
        count = 0;

        Matcher matcher = new TypeSafeMatcher<View>() {
            @Override
            protected boolean matchesSafely(View item) {
                count = ((ListView) item).getCount();
                return true;
            }

            @Override
            public void describeTo(Description description) {
            }
        };

        onView(withId(listViewId)).check(matches(matcher));

        int result = count;
        count = 0;
        return result;
    }

    public static int getCountFromListUsingBoundedMatcher(@IdRes int listViewId) {
        count = 0;

        Matcher<Object> matcher = new BoundedMatcher<Object, String>(String.class) {
            @Override
            protected boolean matchesSafely(String item) {
                count += 1;
                return true;
            }

            @Override
            public void describeTo(Description description) {
            }
        };

        try {
            // do a nonsense operation with no impact
            // because ViewMatchers would only start matching when action is performed on DataInteraction
            onData(matcher).inAdapterView(withId(listViewId)).perform(typeText(""));
        } catch (Exception e) {
        }

        int result = count;
        count = 0;
        return result;
    }

}

Also want to mention that you should use ListView#getCount() instead of ListView#getChildCount():

  • getCount() - number of data items owned by the Adapter, which may be larger than the number of visible views.
  • getChildCount() - number of children in the ViewGroup, which may be reused by the ViewGroup.
Visceral answered 12/6, 2016 at 17:24 Comment(0)
S
0

In Kotlin and for a RecyclerView I used this code highly inspired from the answer of @Cory Roy.

internal object Matchers {
    fun withRecyclerViewSize(size: Int): TypeSafeMatcher<View?> {
        return object : TypeSafeMatcher<View?>() {
            override fun describeMismatchSafely(item: View?, mismatchDescription: Description?) {
                mismatchDescription?.appendText("RecyclerView has ${(item as RecyclerView).childCount} item(s)")
            }

            override fun describeTo(description: Description) {
                description.appendText("RecyclerView should have $size item(s)")
            }

            override fun matchesSafely(item: View?): Boolean {
                return (item as RecyclerView).adapter?.itemCount == size
            }
        }
    }
}

Used like this :

val recyclerView = onView(withId(R.id.rv_students))
recyclerView.check(ViewAssertions.matches(Matchers.withRecyclerViewSize(5)));
Segura answered 13/8, 2023 at 7:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.