How to inject mock dependencies into Android components using Dagger AndroidInjector

Tamás Kozmér
AndroidPub
Published in
4 min readSep 9, 2018

--

A couple of days ago I digged up my old project to try out the new Architecture Components on it, but first I wanted to refactor it a little, since it is more than one year old.

The first thing I did is to change the Dagger configuration to use the new AndroidInjector. This is a relatively new feature from the dagger-android library to remove even more boilerplate code. If you are not familiar with it, you can read about it on the official site. You can also check this commit in my repository, it’s pretty simple.

As I expected my UI tests failed to build after the changes. First let’s see how it looked like before, and what caused the problems.

In the previous implementation I had a reference to the component in my Application class, so it was easy to substitute it with a test component by assigning the field in the test. I have previously written an article about this, you can check it out here:

With the new implementation this is not possible, because we don’t have a reference to the component. The DaggerApplication superclass takes care of the injection instead of us.

This is how the new implementation looks like. Much simpler, and less boilerplate, also less boilerplate in activities and fragments. But how can we test this?

Creating a TestApplication class

We can create a different Application class, that will be used for testing. In this case we won’t subclass the DaggerApplication class, instead we will do the injection in the setUp method of our test classes.

You can see one thing that is worth explaining in this snippet. We implement the HasSupportFragmentInjector interface. This is the interface among many others ( HasActivityInjector, HasServiceInjector , etc…) what is implemented by the DaggerApplication class to inject provided dependencies into Android components. Since we only inject dependencies into Fragments, we don’t need to implement the other interfaces.

To use our TestApplication in instrumented test we also need to create a custom test runner class and set it in our build.gradle file as the testInstrumentationRunner in the defaultConfig closure.

We can specify here which Application class should be used in the tests.

Now we have everything what we needed to inject mocked dependencies into our instrumentation tests. Let’s see how the UserListFragmentTest class looks like after the modification.

You can see that we are doing a pretty similar thing, than in the first version of the class. We are creating the component, but instead of assigning it to the component field in the original CustomApplication class, we use it to inject the dependencies into the TestApplication class.

Removing code duplication

There is still some room for improvement in this code. If we create many instrumentation tests, we will need to add the same piece of code to every test class. There must be a better way to do it.

We can create a TestInjector class, what will get the TestApplicationModule in its constructor and make the injection. We can use this class in our setUp methods instead of writing the same code over and over again.

First I wanted to create a JUnit test rule, but the problem is that test rules are evaluated before the setUp method, and we need to initialize our mocks first.

Making it even more flexible with default arguments

What happens when we have many dependencies provided by our TestApplicationModule, but we only want to mock some of them?

We can create fake implementation of some dependencies and specify them as default arguments in the constructor of our TestApplicationModule class.

In this case we have the flexibility to only mock the dependencies, what we need. As you saw in the previous example, we only needed to mock the UserRepository.

Summary

Android instrumentation testing can be problematic, when we are using the new Dagger AndroidInjector, but there are only a couple of steps, what we need to do to make mocking possible:

  • Create a TestComponent and a TestModule, that will provide fake dependencies.
  • Create a TestApplication class, that implements the appropriate interfaces.
  • Create a custom test runner, that will run our tests by using our TestApplication class.

Thanks for reading my article. If you want to check out the whole code, you can find it in the following Github repository.

If you liked it share it with fellow Android developers or give it a clap or two.

If you have any questions or suggestions leave a comment below.

--

--