Testing Android ViewModels
In my previous post I described how to implement injectable Android view models using Dagger and ViewModel library from Android Architecture Components. In this post I will show a simple way to unit test the view model created then. You can find the full code in the same repository as previously on GitHub.
MainViewModel view model exposes three RxJava
Observables which Activity (
MainActivity) subscribes to in order to receive notifications, e.g. to display an error message. There is also the
getRepo function that triggers fetching some data from the GitHub API and the
data variable that stores the fetched data.
The mentioned members are divided into three interfaces implemented by the view model but it’s mainly for the clarity of the example (you can easily tell which members are used by the Activity and the Fragments).
The only view model’s dependency (provided by Dagger) is
GitHubClient which has a method for fetching some data.
It’s also worth noting that the Activity and the Fragments use the same instance of
MainViewModel. That’s why it can both fetch the data when
LoadingFragment requests it, tell
MainActivity to show an error if anything goes wrong and work as a data store for
DataFragment. In order to achieve this type of sharing the view model instance between the Activity and the Fragments, they must request the view model by passing the Activity reference while getting it:
MainViewModel uses a
GitHubClient implementation that calls the GitHub API using Retrofit HTTP client. In tests you would probably prefer to either mock the server (e.g. with MockWebServer) or just the
GitHubClient implementation so that it won’t make the calls at all. In this example I’m going to use the latter approach (but testing the calls to a mocked server is also a good idea and you can do it separately).
Mock API client
The mocked implementation of the
GitHubClient is very simple. Its constructor accepts a response it should return, an optional error it should throw instead of the response and a scheduler so that we can control the exact moment the data/error is returned. The error and the response are mutable properties so we can adjust them just before calling
Setting things up
I put all the
MainViewModel tests in the
MainViewModelTests class. It has a few properties:
TestObservers for every
TestSchedulerthat is passed to
They are initialized in the
TestObservers record events passed by
Observables and they allow to make assertions about them e.g. if a value has been emitted and what it was exactly.
TestScheduler controls the time when
MockGitHubClient emits responses so that we can defer it and test what happens before the subscription completes (e.g. the progress animation should be still visible).
Writing some tests
Below you can find three simple examples.
Test if positive response from the API triggers
Observable and stores the data for later usage in the
shouldEqual method comes from ShouldKO which I really recommend but you can use any assertions you like.
Test if HTTP exception triggers
Observable with the HTTP-specific error message.
Test if calling
Observable twice so that it should tell the view to show the loader and then to hide it.
As you can see, using
ViewModels and RxJava
Observables gives a very simple way to write unit tests for your code. I believe this great possibility will also encourage you to extract the business logic from the Android application components like Activities so that it can be tested without using instrumented tests or mocking the platform (e.g. with Robolectric).