Kotlin Flows Unit Tests
In the previous article, we went through flows and types of flows. In this blog post, we will go through writing unit tests for flows in the repository and view the model layer. The motivation I had for writing this article was because I encountered the following error when I ran the unit tests that had flows in them:
java.lang.IllegalStateException: This job has not completed yet
I decided to do more research to understand the concept of flows.
Hot flows such as shared and state flows by design do not complete. Due to this reason, when writing unit tests for them, you need to handle them differently. After researching possible solutions, I came across turbine, a library created to test kotlin flows. Turbine allows you to get the value emitted by a flow and test it.
We will start by adding the following dependencies to the build.gradle file:
Next, we will generate a repository test class by right-clicking on the Transactions repository class and selecting generate test class.
In your android test directory, you should see the generated test class.
First, we will add Junit annotation @Runwith() before calling our class.
We will then declare our variables.
Before we write our unit tests, we will first set up our repository
We can now start writing our units tests. Our current repository class has the following methods.
The first unit test we will write will check if our method fun fetchAllTransaction() is returning a flow of a list of transactions.
In the test class, we will start by naming our unit test function with the help of back-ticks; runTest helps in testing coroutines functions and handles uncaught exceptions.
I have divided the units tests into three essential parts in this article. Given, when, and expected.
We will first write our given section as follows:
After, we will write our when section. We will use coEvery, provided by mockk, to help us stub the suspend functions.
The last section is the Expected part. This section will use turbine to get the value emitted by our flow. Then we will assert that the value emitted by the flow will be equal to our list of transactions. We will then use coVerify to ensure that the method transactionDao.getAllTransactions() was called. Lastly, we will use turbine magic function cancelAndConsumeRemainingEvents() to complete our job and avoid the earlier error.
If we now run our test, we should get a green tick showing our test has passed.
We will follow the same steps to write unit tests for the remaining repository methods.
View Model Unit Tests
We will follow the steps we used in our repository layer to test our view model. For example, a test case to check if our total income variable is returning the correct amount will look like this:
To view the rest of the view model tests, click on this link to view a gist showing all the test cases.
That is all for today; I hope you have enjoyed reading the article.