Running Android Espresso Tests with Data Binding (and koin)

Daniel Hartwich
freenet Engineering
5 min readApr 29, 2019

Recently, we at freenet.de started working on an application that uses the data binding library.

Data binding was presented by Google already in September 2015 but has evolved and improved quite a bit. It’s now officially part of Android Jetpack that we developers love to use in our projects in order to reduce boilerplate, accelerate development and build high quality, robust apps.

For this application we had to build a feature that simply displays a list of items and of course we were using data binding for it.

Building the screen was fast and simple and with the help of data binding, we could just pass my items to the adapter and let the binding handle all the rendering and assigning of values to their respective views. So in no time we had the screen up and running and we were ready to submit a pull request.

There’s always more to do!

We hadn’t thought about tests yet (well, we kind of had already 😉)

Of course, we wanted to have tests to ensure that everything looks as expected (UI tests) and that everything works as expected (Unit tests). While Unit tests were easy to write and through mockito we can mock the dependencies to other components, it was not straightforward when we wanted to write UI tests.

Things got interesting when we tried to write espresso tests…

Well, in theory it should be easy, because all we need to do is mock the ViewModel, that is emitting view states, which will be rendered by the activity (or fragment) and afterwards make sure that the expected data is visible.

Turns out this is easier said than done:

How to make sure that the activity you are starting uses your ViewModel instance?

In the application we are working on we are using koin to inject our dependencies. Through this, we are also injecting our view models into our fragments and activities, and this is where we need to hook in. In the setup block of our espresso test we can add our view model to the dependency tree by calling loadKoinModule().

It’s also important to say that in order to override koin modules that are implemented in the Main App, you should have a custom TestApplication and a custom JUnitRunner (check out the example that is linked below to see how to do it).

So now, we just need to observe changes of our LiveData<ViewState> and check that the changes get rendered as expected. This worked fine in the beginning, but after adding a few more tests, we ran into issues, that the tests became flaky, because the data binding had not finished yet and we worked around this by putting Thread.sleep(400) in our tests as a quick fix. But this is not the solution we want. We want something more optimal, so we began researching… After a short amount of time we found this Stack Overflow answer, that gave us the much needed hint:

Espresso does waitForIdle before executing view checks. waitForIdle goes thought IdlingRegistry and waits until every IdlingResource is idle.

LoopingIdlingResource is used in Espresso by default. It waits until looper doesn't have messages in queue, which means that it is idle.

However DataBinding uses different approach to schedule an update, it uses Choreographer.postFrameCallback. So updates are not posted into looper queue and Espresso will not wait for them.

This means, we need our own IdlingResource that looks at our data bindings and allows the test to proceed when all the data binding is finished. Luckily in the same answer, there were also two links to a google-samples repository that already had a partial a solution for our problem:

A DatabindingIdlingResource that works for Fragments and a DatabindingIdlingResourceRule that needs to be applied in our test in order to wait for the DatabindingIdlingResource to idle.

The only remaining problem is, that we need the DatabindingIdlingResource to also wait for Activities.

DatabindingIdlingResource for Activities

Now it works with activities and fragments…

One more… oh yea 🎉

After applying the new IdlingResource in our test we were happy and we thought the tests would finally all be green, but just shortly after running them 2 or 3 times we figured out, that they are still broken / flaky. What were we missing?

And then it struck us… The adapter is also using data binding so we have something like a data bindingception.

So one last step to get our tests to run is to wait for all the children of theRecyclerView to finish their binding before we run our test assertions:

DatabindingIdlingResource for Activities with RecyclerView Support

And that’s it… now Espresso waits until all data bindings have been finished before it starts executing.

We thought this is a nice and small piece of information to share that can be really helpful when you want to write Espresso tests (kudos to you already) and you are using data binding + koin.

Feel free to check out the small example project on GitHub we created and if this article helped you to solve a problem or you just enjoyed reading it, feel free to smash the clap button below to give me feedback. 👏

We are also more than happy to receive any kind of comments!

Interested in how we develop software? Join our team in Hamburg, Germany!

--

--