Writing Testable Android MVVM App: Part 4. ViewModelTest

Brian Lee
3 min readNov 10, 2015

--

In the previous post, we used Dagger 2 to inject a few components and make the app more testable. However, there were 2 open questions at the end:

  1. How do we test that the property change was notified?
  2. How do we test configuration change?

We’ll explore how we can tackle these in this post. The source code for this post is tagged as part4 and available on GitHub.

Verifying Property Change

If you take a look at the ViewModel again, it extends from BaseObservable. That’s what makes Android Data Binding work in the first place. In the unit tests, we just want to verify that when a given field changes, the related property change notification is called. So all we really need to do is add an OnPropertyChangedCallback to the ViewModel under test and check that onPropertyChanged() was called. So let’s create a a base ViewModelTest and do exactly that.

Configuration Change

One of my original goals of the project was to be able to test configuration change in the unit test. We can test this by doing the following:

  1. Get the State by calling ViewModel.getInstanceState().
  2. Create another instance using the State returned.
  3. Check that the new instance has all the values restored.

Let’s add some more helper methods for that to the ViewModelTest we just created.

ClickCountViewModelTest

And with the changes above, we can now test every aspect of ClickCountViewModel.

RecyclerView

Ok, but how do we test RecyclerView based ViewModels? In this case, it’s probably best to test two components separately — the ItemViewModel and the ViewModel containing the RecyclerView. In our sample app, these would be the AndroidVersionItemViewModel and AndroidsVersionsViewModel.

AndroidVersionItemViewModelTest
Since we’re just testing a single item ViewModel, we just want to test how the ViewModel reacts to item change, and any interactions it might have.

AndroidVersionsViewModel
In this ViewModel, we want to test 2 things:

  1. The adapter was initialized with the correct items
  2. Configuration change restores state correctly

In order to do that, let’s update the ViewModel to take Adapter as a constructor parameter, instead of creating its own, so that it’s testable.

AndroidVersionsViewModelTest
Now in the test, we can check if the adapter was initialized with the expected items. We’ll pass in a mock Adapter and use ArgumentCaptor to verify the values.

Normally we can inject some RestApi interface and mock it here, but since we’re using a simple hard-coded array, we’ll put the expected values in the test case.

Status Check

I started with a simple standard Android app that had TextViews, Buttons, and a RecyclerView. Over the past few posts, I’ve iterated to make the app use Android Data Binding with MVVM architecture and made it fully unit testable, including rotation. There are now 14 unit tests in the sample app!

However, there’s one thing that’s not covered yet. Although the unit test checks if the property change notification was sent or not, it can’t actually test if the view was updated. It is possible to forget to bind the items in the layout XML to the ViewModel, or bind the wrong items, which won’t update the view correctly.

So how do we test that? We’ll explore what we can do with Espresso. However, we want to focus on testing just the bindings between the ViewModel and the layout, not the whole interaction or any other aspects of the app. Otherwise it kind of defeats the purpose of making everything unit testable. Let’s explore this in the next post, Writing Testable Android MVVM App: Part 5. Espresso!

--

--