Clean Architecture — Kotlin, Dagger 2, RxJava, MVVM and Unit Testing

In this article, we will see how we implement a Clean architecture for our Android application using Dagger 2 and MVVM especially. All code samples are taken from the repo below:

To start the discussion, it might be worth discussing DI. I have used Dagger Android’s libraries to help with DI across the app. Specifically, I am using the DispatchingAndroidInjector<T> where T is a concrete Android class, such as an Activity, Fragment, Service etc. Only recently did I learn this and yet I feel that it’s power is under-estimated. In a previous incarnation of the repo above, I was using scopes and Components to define application-wide and activity-level dependency objects. (Sigh!)

Let’s look at our Application class to start us off.

As you can see, we are injecting a DispatchingAndroidInjector<T> where T is the Android Activity. What does this do? From the documentation it: Performs members-injection on instances of core Android types (e.g. Activity, Fragment). However, I like to think of it in this way. Given that an Application has many Activities, the DispatchingAndroidInjector enables objects defined in the AppModule to be visible to Activity-level modules that will be built later.

The AppModule looks like this:

As you can see, I have defined a number of application-wide objects such as OkHttpClient, ApiService etc. There is nothing extraordinary of this module. However, it’s corresponding component is quite interesting:

The AppComponent above binds the Application class to the AppModule. But it does more. It also references the ActivityBuilder which looks like this:

The ActivityBuilder above binds the MainActivityModule with the MainActivity. Previously, I remember using custom scopes to confine objects to particular modules, or Android Views (Activities, Fragments) — such as confining a Presenter’s instance to it’s associated Activity. However, the Dagger Android libraries now simplify this to such a degree that we no longer need to provide a Component for the MainActivityModule or any other activity level Dagger Module . The MainActivityModule can then provide the MainActivityViewModel while injecting the objects defined in the AppModule, such as our Rx SchedulerProvider, and any objects constructed using constructor injection such as the Repository instance passed as an argument into the provideViewModel() function below:

Up to this point, we have provided a framework to inject our View Model into the MainActivity. Let’s see the MainActivity code to see how we do this:

Oh wait! That’s strange. Where’s the Dagger Injection code? All that verbose stuff that we used to write. Where’s it gone? It doesn’t exist anymore. Do you remember the ActivityBuilder defined above — that innocuous abstract class? In there, we bound the MainActivityModule to the MainActivity using a @ContributesAndroidInjector. This provided the link between the module and the Activity. But, how did it inject the MainActivityViewModel in the Activity code above? Well, the MainActivity is a subclass of DaggerActivity which contains one interesting line. Let’s look at the source code of the DaggerActivity:

The line AndroidInjection.inject(this); will inject any DI objects referenced by that particular activity — which in this case is the MainActivity. That means, therefore, that if you do not wish to extend your Activity with DaggerActivity, you can insert that line in your onCreate() method.

But a question still remains. How does the annotation, @ContributesAndroidInjector, know it can inject the MainActivityViewModel into the MainActivity? The @ContributesAndroidInjector generates an AndroidInjector<T> where T is a concrete Android class (an Activity, Fragment etc.). The interesting aspect about the AndroidInjector<T> is that it is an interface — its concrete implementation is the DispatchingAndroidInjector<T> that we saw before. There’s a small line in the docs for this class which reveals how this is achieved:

This class relies on an injected mapping from each concrete class to an AndroidInjector.Factory for an AndroidInjector of that class. Each concrete class must have its own entry in the map, even if it extends another class which is already present in the map

Now that we have a brief understanding of how we can use Dagger to provide the DI for our app, now we can start talking about MVVM.

Let’s go back to the MainActivity shown above. We have all our RxJava 2 disposables (or the subscriptions) in the Activity — as held by the CompositeDisposable. What’s the advantage of this? Coming from a background of using MVP, it’s so easy to forget about clearing our Rx subscriptions and disposing of them. In fact, I even remember this causing a bug in one of my apps. Finding the root cause of that bug was extremely difficult because disposing of Rx subscriptions and how they tie into an Activity’s lifecycle is not something we automatically think of when using MVP — we tend to hold the subscriptions (CompositeSubscription or CompositeDisposable) in the Presenter, or a BasePresenter, and this can blind us to the concept that Rx subscriptions should be tied to the lifecycle of the Android view class. In my view, this is one of the most valuable benefits of MVVM over MVP — not from a code point of view, but from a developer’s view of the code — it reminds us of what’s required.

We can now take a closer look at the ViewModel:

As you can see, the key responsibilities of the ViewModel is to provide data from a Repository and enforce Rx Scheduling. The ViewModel has no reference to the Activity or Android view which means we reduce the likelihood of memory leaks.

However, did you notice that the ViewModel does not interact with the ApiService directly — but instead interacts with the Repository class. The Repository class contains a dependency to the ApiService as shown below:

So why have we inserted an extra layer, the Repository layer, in between the ApiService and the ViewModel? Even though the Repository class in this case simply passes the data from the api to the ViewModel, there could be a requirement to store the data into some form of storage. Now we need some logic to determine whether to retrieve data from the API or from local storage and this is a separate responsibility of concern. Having a clear separation of concerns is a key pillar of maintaining Clean Architecture. The ViewModel’s key responsibility is to expose states for the View to consume to ensure the View receives the latest data. The ViewModel’s concern is not to decide where the data comes from; that’s the concern of the Repository class(es).

The following diagram summarises what we have learned so far. The arrows representing the direction of the flow of data.

Data flows from right to left — there is no feedback or bi-directional flow of data.

Let’s see how we can now unit test our ViewModel using Mockito.

One of the biggest issues we faced as a team with the introduction of Kotlin was unit testing. We had unit tests for all our presenters and that was great because last year we felt we had achieved a test coverage that we were pleased with — even though everything wasn’t unit tested, but the fact that all our presenters had unit tests meant that we could be fairly comfortable knowing that our core logic was unit tested. However, the introduction of Kotlin this year changed that — suddenly, we were starting a process of removing unit tests because they all used Mockito and as we know Mockito does not support mocking final classes. Eventually, it got to such a point that we knew something had to change. All the work we achieved in 2016 was being undone by the introduction of Kotlin and that isn’t right.

So a little more research into Mockito and we found this dependency that allows us mock final classes (without using PowerMockito).

testImplementation 'org.mockito:mockito-inline:2.11.0'

The Inline Mockito dependency allows us to mock final classes and methods. Even though there are a few issues with it, as it’s still being developed, it generally worked very well for us. It means we can write our unit tests in the same way as we have done before. Let’s see the unit test for our MainActivityViewModel:

Our unit tests look quite familiar — we wouldn’t automatically deduce that we are using the Mockito Inline library rather than the standard Mockito library. This is what makes the inline library powerful. We created a mock of our dependency to the ViewModel — the Repository is mocked using the @Mock annotation. We then setup the Rx schedulers to use the main thread of the background and foreground schedulers. Once that’s done, we can create an instance of the class under test (the MainActivityViewModel).

As the ViewModel returns Observables, or in this case a Single, we need a means of subscribing to that Single emitted while carrying out our tests. That is where our TestObserver comes in. It allows us to subscribe to the Single<IpAddress> emitted by the ViewModel. We can assert that there were no errors and we can assert that the IpAddress object emitted is the expected outcome. We can unit test our Repository layer code in a similar manner too.

In conclusion, I hope I have been able to impart some of the caveats in developing a Clean Architecture using Kotlin, Dagger 2, RxJava and the MVVM pattern that is testable. Keep coding!!