Skip to main content

Discovering Espresso for Android: wading through the hierarchical thicket

The Android Lollipop update brought a hard nut to crack for the testers who use Espresso, represented by RecyclerView.

So far the app I'm testing contains this element in couple of places. While I was writing tests for them I found out that it was not so easy and obvious. Thanks to Espresso authors, version 2.0 has the basic RecyclerView actions support which is honestly not enough and is not convenient sometimes.

The example of RecyclerView action:
import static android.support.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition;
.
.
    @Test
    public void testSomething() {
        onView(withId(R.id.recycler_view_id)).perform(actionOnItemAtPosition(1, click()));
    }
The activity under test has the following structure - it contains the RecyclerView element which is populated with some data. Let's call it the Feed. Each element in Feed is the Feed Post represented by FrameLayout. Of course every FrameLayout has the same layout elements inside as it's neighbors. It contains header with text and footer with like ImageView and TextView used to show number of likes.

What I just described represented by below image:



Now let's try to implement this test case:
  1. click the like ImageView in 3rd RecyclerView item (FameLayout 3), 
  2. check that number of likes changed after the click. 

In my tests I don't want to rely on the Post position in the RecyclerView, because I run multiple tests in parallel and some of them can create new Posts and push down the target one. I'd like to rely on some unique element of the Post instead.

Now I'll focus on the layout. Target ImageView and TextView are marked in red color.


Actually I can't click the like image (ImageView with id=like_image) directly, based on it's id, since this will lead us to multiple matches issue.

But what if we climb in the FrameLayout hierarchy up (from like ImageView) until we found any element with the unique value. In our case the unique is the text in Post header (TextView with id=header_text).

Now we'll find the way how to tie like image with header text. We'll go up in the hierarchy from like image using withParent() method until we reach footer (LinearLayout with id=footer)  which is the sibling of header (LinearLayout with id=header), which contains child with unique text (follow arrows on the image). And the code is:
private void clickOnLikeIconOnPostWithText(String postText){
    onView(allOf(withParent(
            allOf(withParent(
                    allOf(hasSibling(
                            allOf(withId(R.id.header), withChild(withText(postText)))),
                        withId(R.id.footer))),
                withId(R.id.footer_like))),
        withId(R.id.like_image))).perform(click());
}
And the similar code for checking the like text value (TextView with id=like_text):
private void checkLikesText(Matcher<View> likeTextMatcher, String postText){
    onView(allOf(withParent(
            allOf(withParent(
                    allOf(hasSibling(
                            allOf(withId(R.id.header), withChild(withText(postText)))),
                        withId(R.id.footer))),
                withId(R.id.footer_like))),
        withId(R.id.like_text))).check(matches(likeTextMatcher));
}
Finally the usage is:
@Test
public void testPostLike() {
    //like - 1 like count
    clickOnLikeIconOnPostWithText("UNIQUE_TEXT_3");
    checkLikesText(withText("1"),"UNIQUE_TEXT_3");
}
Looks a bit unusual and complicated but it works.

Comments

Popular posts from this blog

Discovering Espresso for Android: matching and asserting view with text.

After more than a month of using great test tool from Google - Espresso for Android, I'd like to share with you some of my experience. I assume that you've already added espresso jar into your project, spent some time playing with Espresso samples and have basic understanding how this tool works. In this post I'll show how to match particular view with text or assert that it contains (or not) specified Strings. Before we start, you have to take a look at Hamcrest matchers - Hamcrest tutorial and API Reference Documentation , which are used together with Espresso's ViewAssertions and ViewMatchers and included into Espresso standalone library. Pay more attention to Matcher<java.lang.String> matchers. So, here we go. For simplicity following String "XXYYZZ" will be used as a expected text pattern. Espresso ViewMatchers class implements two String matcher methods withText() and withContentDescription() which will match a view which text is equal

Discovering Espresso for Android: creating custom Matchers.

Hi! This time I'll talk about custom Matchers that can be used with Espresso for Android (and not only). We'll go through steps how to create them and I'll provide you examples of already existing and very useful ones. First of all a couple of words about Hamcrest library , which provides us with common matchers and possibility to create custom matchers, to pay tribute to it's authors. From Humcrest project main page - Hamcrest provides a library of matcher objects (also known as constraints or predicates) allowing 'match' rules to be defined declaratively, to be used in other frameworks. Typical scenarios include testing frameworks, mocking libraries and UI validation rules. In one of my previous post I've described already how to use some custom Hamcrest matchers. The base idea is that matcher is initialized with the expected values, which are compared against the actual object we are matching when invoking it. Among of the common matchers you

Preparing android emulator for UI test automation.

This post is about setting up android emulator for UI test automation. Properly configured emulator is the basis for reliable tests. Hundreds or thousands of professionally written test cases is great but if they become flaky because of the environment they are running on, their value reduces a lot. I will give you a couple of advices I'm following in my test automation projects. In general we will go through below topics: Managing emulator system animations Controlling soft keyboard appearance Changing emulator system locale Tweaking first and second points will reduce to minimum flakiness in our automated tests which can be caused by emulator. For those who are lazy to read the whole article at the bottom of the post I shared youtube video where I describe the same points with one more additional hint on top :) 1. There are three types of system animation we may control: window animation scale transition animation scale animator duration scale Emulator