Hassle-free Android UI tests using Dagger 2
You may be wondering: “Why do we need yet another article about UI testing of Android apps that make use of Dagger 2 library? There are plenty of tutorials already.” Well, if I didn’t have anything to add to this conversation I wouldn’t be writing to you.
The main problem I was trying to solve is to remove all the hassle related to injecting mocked or stubbed dependencies into the activities. Of course one can find many pieces of advice on how to do this proper way. But all of them involve creation of additional modules and components that are only used to provide test dependencies. What if I don’t want to do this? It’s too much work for me! There should be an easier way. And it turns out there is…
Before we continue let me say that the method I’m about to show you works well with any presentation layer organization (not only MVP - Model-View-Presenter) as long as there are dependencies which you want to control that are injected in the activity.
So let’s get started, shall we? Imagine that you have a welcome screen in your app implemented using a simple Android activity named WelcomeActivity. To inject dependencies in the activity you create a component like this one:
And the required dependencies are provided by the WelcomeModule:
Pretty basic stuff. Now, how do we inject our dependencies into the WelcomeActivity? We do it in the Activity#onCreate(Bundle) method. The main trick here is how we actually create a WelcomeComponent instance that is then used to perform dependency injection. In this case it’s created and managed by the global AndroidApplication class. That’ll come in handy when we later write UI tests for our welcome screen.
And here’s our main application class:
In order to test our activity we need to be able to return a test version of the WelcomeComponent when WelcomeActivity requests it in the onCreate method. It can be achieved by extending our main application class and overriding AndroidApplication#createWelcomeComponent() method:
From this point onwards it doesn’t matter whether you prefer to write UI tests using Espresso or Robolectric or any other testing framework — you’ll always be able to inject dependencies created specifically for the testing purpose.
For example, let’s see how we would set up a Robolectric test for the WelcomeActivity. All we need to do is:
- Create an instance of the WelcomeComponent.
- Override the method that performs the dependency injection (WelcomeComponent#inject(WelcomeActivity) in this case).
- Tell our main test application class to return this component when requested instead of creating an actual one.
The same approach works well for the Espresso tests also! The only difference is the way you specify what application class should be used when running the tests. You can do this by extending default AndroidJUnitRunner and setting testInstrumentationRunner property in the build.gradle file to point to our custom runner:
Congratulations! In less than 5 minutes you were able to start writing hassle-free Android UI tests. Forget about unnecessary Dagger 2 modules created solely for the testing purpose.
This approach was successfully tested when developing AgileFit application I’ve been working on recently. Go ahead and try it to see whether writing tests this way helped me create bug-free user experience :) Bonus: you can even use this approach in conjunction with the Spoon library to automate screenshot capturing process for the Google Play Store app page.
Hope this article did show you a more elegant way of writing UI tests!