ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Follow publication

Testing Espresso Matchers

If you are using instrumentation tests in your Android app, it is likely that you are using Espresso— allowing you to define expectations about your app screens and how to interact with them.

During your day-by-day as a developer you will eventually implement some custom views. However, Espresso won’t have the ability to assert the specific behaviors of your custom view out of the box. To make it possible you will have to create your own Espresso matchers. In this article I want to show you how to create a simple Matcher and how to run tests for it in the JVM.

The example we will follow is the implementation of a custom Button that has a loading state. I will break it down into 3 steps: naive implementation of the LoadingButton , creation of an appropriate Matcher and the test for that Matcher . At the end I will just showcase a simple usage of our new tested Matcher.

The `LoadingButton` in non-loading and loading states
  1. Creating the LoadingButton

For the sake of simplicity I’m not going to focus on the implementation of the LoadingButton. The only relevant part is that we would have a setter/getter for the loading state.

2. Creating the WithButtonLoading Matcher

When creating a custom Matcher for a custom property of your View you should extend a BoundedMatcher<T, S extends T> . When extending it you will have to override two methods:

  • describeTo(description: Description) — here you should add a relevant message to description so that you can understand better when this matcher assertion fails.
  • matchesSafely(item: S): Boolean — you should return a Boolean stating whether or not the given item respects your logic.

In our example we would do as follows:

In this case we would use describeTo to describe our component (a button in a loading state) and the matchesSafely to assert that the given item is in the desired loading state.

An important point is that I actually made this class internal as this exposes an implementation detail. It is an observed good practice on Espresso matchers to have public wrappers of the internal matchers that provide friendlier/more readable APIs.

We would then define a public ButtonMatchers that provides methods to create matchers that check if the button is loading or not loading.

3. Creating the Test

In order to test this matcher in with a fast approach and with no need to run instrumentation tests, we will leverage FragmentScenario which are able to run on top of JVM. This will create reliable and fast tests when compared with the instrumentation tests.

The idea is that we will use FragmentScenario + Roboelectrict to launch a Fragment that inflates our LoadingButton , so that we can interact with it and perform assertions regarding the Matcher behavior.

Below you can see that we are testing the behavior of ButtonMatchers.isLoading matcher: if the Matcher behaves correctly when the button is loading and not loading.

The magic happens on launchViewInFragment , which takes a function that creates the View that will be inflated in the Fragment .

The internals of launchViewInFragment make use of FragmentScenario to setup and launch the test.

Set of helpers to inflate a single View and launch in the context of a Fragment Scenario.

If we then run our tests and, the output on Android Studio will be the following:

You can see that it has a initial overheard time spent, but after that the tests run really fast. And the more tests you have the less the overhead will be noticeable in the full test run time.

To finalize I just wanted to briefly show how we would use our new Matchers in an instrumentation test. In this example, we assume the button loading state is toggled everytime you click it. You can see the matchers being used on the assertButtonIsLoading and assertButtonIsNotLoading .

You can find a sample project describing this example here.

References:

Published in ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Responses (1)

Write a response