****Update****

In Dagger 2.19 some of the APIs have been changed (https://github.com/google/dagger/releases/tag/dagger-2.19) so I have updated the code snippets

The Dagger team did a great job with AndroidInjector, before introducing AndroidInjector there were a lot of patterns of how to use Dagger 2 correctly, and even more ways of how to inject fake/mock objects for a test. Fortunately for us, the Dagger team built a custom implementation for Android making the development easier and without the need to look the best solution since they provided such solution for us.

In additional to simplify the production code, they also simplify the overheads that we need to write in order to unit test our Activities using Espresso framework.

Basic App As Simple Use Case

Let’s consider a simple Activity that has only FAB and TextView, the text of the TextView will be “Hello World!” until clicking on the FAB, then the text will change to “FAB was clicked”.

For the simplicity of this example I’ll use MVP pattern, upon clicking on the FAB the View will inform the Presenter that the FAB has been clicked and as result the Presenter will ask the View to show the text “FAB was clicked”.

Simple AndroidInjector Implementation

Let’s see first the contract between the View and the Presenter:

We will inject the Presenter to the Activity so in the test, we will inject mock of the Presenter instead of real implementation in order to verify that the Presenter is being called upon clicking on the FAB, our MainActivity looks like this:

There a lot of great resources on the web of how we can use the AndroidInjector, our implementation look like this:

How AndroidInjector Works

Now we reach the point that we want to write a test that injects the mock Presenter, so we will be able to verify that the method on the Presenter has been called when clicking of the FAB. The main player in AndroidInjector is the property that we added to the MyApp class DispatchingActivityInjector, this property holds a map between the class of Activity to its injector factory provider. In simple words, each item in this map contains Activity class as key and the value of this item is eventually the code that assigns values to the injected properties of the Activity.

In our example, this map will hold a pair of MainActivity class to the code that will create a new MainPresenter using the provideUserAction method in the MainActivityModule.

Build Fake AndroidInjector For Test

For testing of a single Activity we need item in the map all which will contain pair of the class of the Activity under test and some code that assigns a mock Presenter to the instance of the Activity.

Our plan to test the Activity is pretty simple, we will create a function that gets a single parameter, lambda with MainActivity receiver, in the function we will create AndroidInjector that runs this lambda, factory that returns the injector and the function itself will return an instance of DispatchingAndroidInjector that holds the map between MainActivity class to the provider of the factory.

Now that we have this function we can just call before launching the Activity and init the Activity’s injected fields with the values that we want

We can take it to an additional step and make the function a bit more general and now we don’t need to write it once again for each Activity test

Conclusions

In the old way of using dagger we had to use fake modules and components for each Activity and sometimes also even we had to use special AndroidJUnitRunner, using AndroidInjector we saw how we can test the code with minimal overhead code that written once for all Activity test.

Happy testing