How to synchronize Espresso UI tests

We use Espresso to write effective and reliable UI tests. This testing framework provides a very well maintained set of APIs that ensures a solid and flexible testing environment.

In order to maintain this flexibility, at some point we ought to integrate an implementation of the IdlingResources.

What is an Idling Resource? As Android Developers Documentation states:

An idling resource represents an asynchronous operation whose results affect subsequent operations in a UI test.

Why do you need it?

By registering idling resources with Espresso, you can validate these asynchronous operations more reliably when testing your app.

In plain English, Idling Resources synchronize Espresso tests with your app’s background tasks.

If you haven’t encountered an Espresso PerformException yet, you might be wondering what’s all this fuss about synchronizing Espresso, right?

Let’s assume a simple scenario where you want to perform checks on some items within your ListView , but only after data has been loaded from your API. Let’s try executing some right away like this:

In most of the cases in this scenario, you will end up with an exception:

android.support.test.espresso.PerformException: Error performing 'load adapter data' on view 'with id:'

Why is this happening?

In short, while your app was busy trading data in its background threads, your impatient Espresso test wanted to execute some checks immediately. As your request takes some time to process, the test had pretty much no content to interact with, therefore throwing that nasty exception.

In this case, trying to perform some checks on affected views when data is being retrieved remotely might ruin your testing experience immediately.

How to fix this?

Obviously, we could solve this by adding an artificial delay (solution illustrated in some of SO answers to this issue) either by adding code like SystemClock.sleep(period) or Thread.sleep(period) . Yet with this approach, we might end up having inflexible and slow tests — not what we wanted in the first place.

In order to solve this in a clean and effective manner, we can integrate in our application an implementation of the IdlingResources, and for the sake of simplicity, let’s make it CountingIdlingResource — one of the easiest to understand resource that comes bundled within the framework.

How does CountingIdlingResource work?

This resource acts on the simple concept of incrementing and decrementing. It maintains a counter of active tasks. When the counter is zero, the resource is considered idle, and when the counter is non-zero, the app is busy and therefore the resource is active.

! If you want to have a better understanding on howCountingIdlingResource internals work, check the below Extensive and explanatory custom implementation.

! Don’t forget to add to your build.gradle file the following dependency:

‘com.android.support.test.espresso:espresso-idling-resource:3.0.2’

Quick implementation:

A CountingIdlingResourcecan be easily used throughout the app by simply declaring a global variable in the Activity, Presenter or in any other component you are conducting the background tasks:

CountingIdlingResource mIdlingRes = new CountingIdlingResource("name");

We then increment it when Espresso should wait: mIdlingRes.increment(); and as soon as the operation are finished, tests should resume and we then add mIdlingRes.decrement();

Also, we need a method in this specific component to get its resource:

public CountingIdlingResource getIdlingResourceInTest() { 
        return mIdlingRes;
}

Now we’re all set to go to use the IdlingResource in the Test:

Note: If you still didn’t get how to use this resource, you should read the complementary below custom implementation of EspressoIdlingResource.

Extensive and explanatory custom implementation:

For a better understanding on how CountingIdlingResource mechanism acts, we’ll now display a simple custom implementation of EspressoIdlingResource that has been extracted right from Google’s Android Architecture Blueprints, more precisely: MVP + Dagger2 + Dagger-Android.

Let’s create a SimpleCountingIdlingResource class that implements IdlingResource:

Now let’s create the actual custom EspressoIdlingResource:

How to use it? Assuming the same basic case scenario as above:

You are trying to test and assess some visual interactions (or results) only after some data has been asynchronously loaded from a data source. As mentioned above, trying to do some tests with Espresso right away might exactly get you a PerformException .

To avoid this, we can now programatically tell Espresso when the app is busy loading that data. In order to achieve this, in your component that is responsible of managing data transactions (in this example: the Presenter — from MVP presentation pattern), you could do something like this:

Now, it is easy to expand this example to other scenarios. As shown in both implementations, we simply add this line before an action (involved in a test) where Espresso should wait:

EspressoIdlingResource.increment(); // App is busy until further notice

At the completion of the action, notify Espresso that it can resume its tests:

EspressoIdlingResource.decrement(); // Set app as idle.

Let’s not forget to set up our implementation of EspressoIdlingResource in every test that targets components where Espresso has been notified.

You can do this by simply adding these lines when preparing test fixtures:

And that’s pretty much it!

We can now enjoy and sit back while EspressoIdlingResource handles all the synchronization that was required. There is no need to use those nasty bad practices anymore that turn the Espresso UI tests into unreliable pieces of code.


I want you focused so take a break, and see ya in the next article! And remember, if you enjoyed this article, you can buy me a coffee using the coffee bottom widget!

3+
%d bloggers like this: