Somehow it seems that testing is still treated like an afterthought in mobile development. The introduction of the Espresso test framework in the Android Testing Support Library improved the situation a little bit, but the documentation is limited and it can be hard to debug problems. And you will run into problems, because testing is hard to learn when there are so few examples to learn from.

Anyway, I recently created my first custom ViewMatcher for Espresso and I figured I would like to share it here. I was building a simple form with some EditText views as input fields, and these fields should display an error message when the user entered an invalid input.

Android TextView with Error Message

Android TextView with error message

In order to test this, my Espresso test enters an invalid value in one of the fields, presses “submit” and checks that the field is actually displaying an error message.

[java]
@Test
public void check() {
Espresso
.onView(ViewMatchers.withId((R.id.email)))
.perform(ViewActions.typeText("foo"));
Espresso
.onView(ViewMatchers.withId(R.id.submit))
.perform(ViewActions.click());
Espresso
.onView(ViewMatchers.withId((R.id.email)))
.check(ViewAssertions.matches(
ErrorTextMatchers.withErrorText(Matchers.containsString("email address is invalid"))));
}
[/java]

The real magic happens inside the ErrorTextMatchers helper class:

[java]
public final class ErrorTextMatchers {

/**
* Returns a matcher that matches {@link TextView}s based on text property value.
*
* @param stringMatcher {@link Matcher} of {@link String} with text to match
*/
@NonNull
public static Matcher<View> withErrorText(final Matcher<String> stringMatcher) {

return new BoundedMatcher<View, TextView>(TextView.class) {

@Override
public void describeTo(final Description description) {
description.appendText("with error text: ");
stringMatcher.describeTo(description);
}

@Override
public boolean matchesSafely(final TextView textView) {
return stringMatcher.matches(textView.getError().toString());
}
};
}
}
[/java]

The main details of the implementation are as follows. We make sure that the matcher will only match children of the TextView class by returning a BoundedMatcher from withErrorText(). This makes it very easy to implement the matching logic itself in BoundedMatcher.matchesSafely(): simply take the getError() method from the TextView and feed it to the next Matcher. Finally, we have a simple implementation of the describeTo() method, which is only used to generate debug output to the console.

In conclusion, it turns out to be pretty straightforward to create your own custom ViewMatcher. Who knew? Perhaps there is still hope for testing mobile apps…

You can find an example project with the ErrorTextMatchers on GitHub: github.com/smuldr/espresso-errortext-matcher.