Android Architecture Components: Testing your ViewModel LiveData

Last week I pushed a fork of the Buffer Android Boilerplate to a public repository — the difference with this fork is that it uses the new architecture components (ViewModels in the presentation layer and Room in the cache layer). If you haven’t seen it yet, you can do so here 👉

https://github.com/bufferapp/clean-architecture-components-boilerplate

But we’re not here to talk about the boilerplate itself! Because you’re going to be writing tests for your ViewModels (I hope 😄), we’re here to take a really quick look at two simple ways in which you can verify that your LiveData is being updated based on the operations taking place within your ViewModel — this will allow us to ensure that our ViewModel classes remain functional and maintainable.

To begin with, we’re going to need a ViewModel class to reference when we’re talking about these tests that we’re going to write. I’m going to go ahead and take this one from the boilerplate:


https://gist.github.com/hitherejoe/fcbc4317e95041c621478dcf71738c21

You can see that the ViewModel instance contains a Use Case class called GetBufferoos — some projects that use ViewModels will be communicating directly with a repository, this will work the same way for your tests — you will just need to mock the corresponding class that is handling the retrieval of your data.

There are two ways in which we can verify our ViewModels are triggering the right events for our Views.

Verifying Observer onChanged() events

The first way in which we can test our ViewModels is by using mockito to verify that our observer onChanged() is called when a postValue() method should have been triggered within our ViewModel. For this example let’s take our fetchBufferoos() method from the code snippet above.

We’re going to write a test that verifies that the progress state is triggered within our ViewModel:

@Test
fun fetchBufferoosTriggersLoadingState() {
    bufferoosViewModel.getBufferoos().observeForever(observer)
    bufferoosViewModel.fetchBufferoos()

verify(observer).onChanged(Resource(ResourceState.LOADING))
}

This test is doing one simple thing, checking that when we call the fetchBufferoos() method, our livedata is updated with a change event with the ResourceState value of LOADING. But how is this working?

To begin with, you need to add a mock Observer instance to your test class:

@Mock lateinit var observer: Observer<Resource<List<BufferooView>>>

You’ll notice that we then use this mock observer in our tests in this line:

bufferoosViewModel.getBufferoos().observeForever(observer)

If our livedata doesn’t have an observer, then onChanged events will not be emitted — this observer instance allows us to add a mock observer to our livedata so that we can verify the data is changed when we expect it to.


Asserting LiveData values

If we want to assert specific data has been set within our tests, then we can do in a similar way to above. To be honest, these approaches are pretty similar so it’s probably down to personal preference which you use. Our test method only changes slightly:

@Test
fun fetchBufferoosTriggersLoadingState() {
    bufferoosViewModel.getBufferoos().observeForever(observer)
    bufferoosViewModel.fetchBufferoos()

    assert(bufferoosViewModel.getBufferoos().value.status ==     
        ResourceState.LOADING)
}

The only difference within the test method is this:

assert(bufferoosViewModel.getBufferoos().value.status ==     
        ResourceState.LOADING)

All we are doing here is fetching the livedata instance from our ViewModel, retrieving its value and asserting that it matches the desired value.


The differences between these two approaches? The main key here is the focus of the test methods.

For example, imagine if we had a fetchBufferoosReturnsBufferoos() test method and we asserted that the data had been changed like so:

verify(observer).onChanged(
        Resource(ResourceState.SUCCESS, bufferoos))

Whilst in most cases this ok, some developers may prefer to split this test into two seperate methods:

  • fetchBufferoosReturnsSuccessState() — Asserting the result like so:
assert(bufferoosViewModel.getBufferoos().value.status ==     
        ResourceState.SUCCESS)
  • fetchBufferoosReturnsBufferoos() — Asserting the result like so:
assert(bufferoosViewModel.getBufferoos().value.data == bufferoos)

The above methods are a simple introduction to how you can write unit tests for your ViewModel methods. I’m looking forward to sharing more to do with the testing of architecture components as I learn more 🙂

https://github.com/bufferapp/clean-architecture-components-boilerplate

Leave a Reply

Your email address will not be published. Required fields are marked *