UI Testing on Android with Dagger, Espresso and Mockito.
Goals that were our motivation to create new testing tools:
- Create an architecture around instrumental tests, coherent for both iOS and Android platforms.
- Test the application according to the specified test scenarios, based on the same pre-prepared data from the server.
- For Android we have resigned from running tests on our CI (Continuous Integration), but we’ve decided to use new tool from Google Firebase: Firebase Test Lab.
- Display test results on a website with all necessary information about project.
Espresso and Mockito
Two most popular UI test frameworks on Android are Espresso and Robotium. We decided to go with Espresso as it has the biggest community and really good documentation that thanks to its simplicity allows to create from most basic tests to really complex test scenarios. The second choice was obviously Mockito which gives us opportunity to ensure that objects perform the actions that are expected from them. Also it works well with dependency injection libraries like Dagger.
How to prepare for UI testing
In order to create proper UI test we need to differentiate them from server side (in most cases). There should not be a situation in which tests do not pass due to server fault. To avoid such situation we can use dependency injection framework Dagger and for networking Retrofit. These are the basic libraries we use in our projects. I will try to guide you step by step through preparing test environment.
Let’s start with basics of Dagger. Create component in Application class, add necessary modules which will be used in our project. One of the modules will be responsible for providing API services. Create a method that returns already built component, then inject this component into onCreate().
In order to mock server responses for testing purposes, we need to create new Application class that will inherit after previous one.
Thanks to this approach we can overwrite the method with component and build it from scratch, along with overwritten module from our API service that includes earlier created server responses.
As you can see in example above we used Mockito to mock SharedPreferences and assume results. It’s worth adding that we can provide some logic to our service to create more testing capabilities.
We still need a new runner that will point to new application class with overwritten data.
We cannot forget about changes in build.gradle
All tests with new TestApp.class and MockTestRunner.class should be added at androidTest package.
This implementation makes your app fully independent from server and gives ability to manipulate pseudo server responses.
Let someone (or something) do it for you!
With this preparation we can safely write full fledged instrumentation tests, but what’s next? Is this the most optimal and automated solution?
Nope it’s not.
The problem is that you will run UI tests occasionally. It takes a lot of time, resources and makes your Android Studio and phone busy for some time.
This is why we decided to use Firebase Test Lab. The greatest advantage of this solution is the variety of devices we can use and possibility to run instrumentation tests on Google servers. Newest Android Studio allows us to run UI tests on Test Lab platform, but unfortunately the Android Studio resources are assigned to this task until the end.
We took a step further and automate the whole process. We can divide the the process into 3 stages: Test Lab configuration, processing the test results and displaying them on a website. Everything is managed by our CI.
- Test Lab configuration. To simplify configuration process and make it readable for CI we created gradle plugin: Firebase Test Lab for Android. It allows to configure the Test Lab on build.gradle level, and based on that we can run tests on Firebase, afterwards results are downloaded to specified location.
- Results processing. We used Python scripts here. Downloaded test results are processed into json file with predefined formatting.
By proper task management on our CI we achieved an automatic tool that monitors whether our continuous changes in projects, allowing the application to run as we expect. Another advantage of this solution is that we ease the work for QA team that does not have to test manually what has been already tested on Firebase. Another thing worth to mention is stability of the Firebase Test Lab. We do not have to worry that our tests won’t pass due to technical and software reasons, i.e. animations or unexpected notification which will cover screen.
If you would like to know how it looks on iOS check this article.
If you like my work hit ❤ button and let me know what you think in comments!