Sitemap

ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Unit Test a ViewModel logic with Cloud Firestore operations.

3 min readOct 29, 2019

--

Press enter or click to view image in full size

I struggled for a while, trying to unit test the logic of my ViewModel when I had some Cloud Firestore operations to do. How to mock the result of my query? How to tell my tests to wait for the “onSucceedListener” to emit?

I didn’t like the whole listener logic making my code ugly, heavy and hard to test…

I used to have something like that:

Old Repository logic
Old viewModel logic

And try to do a fake Task class in my test but it was heavy and complicated and didn’t work for all kind of task.

So I look into how to take advantage of the Kotlin Coroutines to wait for the result of my task to be here without blocking the UI.

This article explain how to convert your Firestore tasks into suspend functions you can execute in your View Model and unit test them easily.

We assume that the reader has basic understanding of coroutine functions, MVVM architecture and unit test.

Our application can create and get an object User from the Cloud Firestore database.

Your project should be in Kotlin and you should have the following dependencies

The User Object

It’s a simple data class with a couple of attributes:

the User class

Sealed class to hold the result

The sealed class Result holds the result of the Firestore operation and its status (Success, Error, Canceled). It allows us to know if our operation succeed or not and get the eventual error message Firestore returns.

wrapper around firestore answer

Create a Coroutine from a Firestore Task

We now need to convert our Firestore Task into a coroutine function that will wait for the answer of the query and emit a Result object with the corresponding data.

We simply create an extension for Task object, await(), that will return:

  • Result.Success with the data if the query was successful
  • Result.Error with the corresponding error message if an error happened
  • Result.Canceled with an eventual error message if the query was canceled.

This code was took and modified from: https://github.com/Kotlin/kotlinx.coroutines

Repository, Fake and Implementation

In order to test the actions of our repository easily, we declare all the methods of our repository in an interface then to do an implementation for our application with the real Firestore queries and a fake repository for our test that sends fake results.

User Repository Interface:

User Repository Implementation:

Fake User Reposiory for Unit test:

The ViewModel implementation

The ViewModel now looks like this:

It executes the coroutines function defined in the repository, wait for the result and emit the data corresponding (user information or a message).

The view can simply subscribes to those Live Data to update the UI.

I didn’t write the view implementation. A lot of tutorial are available online to learn more about MVVM architecture and Live Data in Android.

The ViewModel tests:

It’s now time to test our ViewModel logic.

In order to make testing easier I have created a couple of helpers:

  • LiveDataTestUtil: used to test a LiveData, it wait for the result to be emitted then gets its value
  • A variable testUser: generates a User with its data.

I can then simply write my unit test by executing my ViewModel methods and use assertEquals to verify that the Live Data emitted have the right values:

Here’s the best solution I found to unit test my ViewModel with Firestore operations. Please let me know what you think and share you way to do it.

--

--

ProAndroidDev
ProAndroidDev

Published in ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Gaëlle Minisini
Gaëlle Minisini

Written by Gaëlle Minisini

Android Engineer solving mobile performance challenges. Sharing practical Android development insights from Nelson, BC. Always learning! @League

Responses (5)

In your test you mocked your getUserFromFirestore() to return successful result, what if there was an error or it was cancelled? How to handle these three cases?

--

Thank you Gaëlle, your article not only saved me a lot of pain, but your effort has also made me understand the integration of coroutines to firestore and MVVM. Thanks :)

--

Recommended from Medium

See more recommendations