Now that we're done with the basics and you finally get the hang of the allOf()
function by using multiple ViewMatchers
we can continue the journey of fixing a different case that leads to AmbiguousViewMatcherException
. Consider the following UI layout where you need to click the check box beside the text "Tokyo Imperial Palace". The problem with this one is that, using multiple ViewMatchers to filter out unique attributes will not work because the checkboxes have identical attributes.

Test engineers who's been using selenium or other UI automation tool may solve this problem by getting all the checkboxes on the screen and then clicking the checkbox that you want by index. It is a valid solution and something that you can do with the help of UIAutomator
but the problem with this solution is that it won't work if the content is dynamic. That means that when a specific content has moved it's position the test will not work as intended.
One approach that I highly recommend is to use the View Hierarchy of the current screen and use the parent, descendant and sibling layout with respect to the UI element that you want to take action to. If you've been exploring at the ViewMatchers
documentation, you've probably stumbled the following functions.
withParent()
hasDescendant()
hasSibling()
The above ViewMatchers
are different than the ViewMatchers
that we've been discussing in the past two (1, 2) articles because it doesn't match by attribute. Instead it accepts another ViewMatcher
to look if such attributes are present on it's descendant, sibling or parent container.

Before we go to the solution I need to give a brief example on how View Hierarchies work. UI elements in an android app are arranged with the help of layouts. A good analogy is that it's similar to a website's nested html
tags with different class
and ids
. What you see above is an example of how the checkboxes are placed in the app. The TravelContainerLayout
is the the Parent of HeaderLayout
and EntryContainerLayout
. While the TravelCheckbox
and TravelText
are the descendants of the EntryContainerLayout
.
Now that we know how View Hierarchies and Android Layouts work let's go to the code on how we can click the checkbox of "Tokyo Imperial Palace". In narrative format, the quick solution is just easy. Find a check box that has a sibling with a text of "Tokyo Imperial Palace".
Converting it to code will look something like this
Espresso.onView(
allOf(
withId(R.id.TravelCheckbox),
hasSibling(
withText("Tokyo Imperial Palace")
)
)
).perform(click())
Always remember that onView()
will always accepts a single argument of type Matcher
. If you need to add additional criteria to narrow the search use the allOf()
function. ViewMatchers
like hasSibling()
also accepts a single parameter of type Matcher
and that also applies to hasDescendant()
and withParent()
. And if you need to use multiple attributes to look for an element inside a descendant or sibling, remember that
You can passallOf()
if you need to use multiple ViewMatchers insidehasDescendant()
,withParent()
andhasSibling
Necessary for Mastery
The more complicated the layout of the android app you are testing, the more you need to use hasSibling()
, hasDescendant()
and withParent()
. I'll admit that it's kinda complex and very hard to read especially when the Application under test has deep nesting of layouts but I think that Google's Espresso, at the time of this writing, is the only reliable library that does it's job well for automating ui elements with identical attributes.
Comments