Diving into Kotlin DSL Part-3: Unit testing with Kotlin DSL in Android
In Android, JUnit and Mockito are used most often for local unit tests. If you are one of them who don’t prefer to write unit test of your code, I strongly recommend you to write unit tests to avoid issues in production.
In case you don’t know what Kotlin DSL is all about, I’ll recommend you to read previous blogs of this series to get a basic idea about the Kotlin DSL
and to set up Kotlin DSL with Android studio
Now if you have done that, let's get started with Android unit testing.
Before diving into the details of unit tests, I assume you already know a few basic things regarding unit tests, like how to use JUnit and Mockito. Still, I’ll try to make it easy for you to understand. There are certain steps to write a local unit test.
Step 1: Set up your testing environment
Initially, it requires few dependencies since we have already set up DSL in our previous blog we will add dependencies in our “Dependencies.kt” file then we will use its reference in build.gradle.
Here I have added required libraries for unit testing in Dependencies.kt. You can ignore daggerMock if you are not using Dagger. You can try this library which has useful kotlin extension, I found it handy while using Mockito.
"com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0"
Now, we will add these dependencies in build.gradle
dependencies {
..... //unittest
testImplementation TestLibs.junit
androidTestImplementation TestLibs.testRunner testImplementation UnitTest.kotlinTest
testImplementation UnitTest.mockitoCore
testImplementation UnitTest.mockitoKotlin
testImplementation UnitTest.mockitoInline
}
Step 2: Create a local unit test class
Create a class underhood the app/build/src/test directory according to your packages.
To better understanding, I have created a sample app which has a ViewModel named as RandomUserViewModel.
Here is our ViewModel app/src/main/java/com/unittestsample/app/presentation/user/RandomUserViewModel.kt
So now we will be writing the test cases for RandomUserViewModel. To create unit test, here I have created a class
app/src/test/java/com/unittestsample/app/presentation/user/RandomUserViewModelUnitTestNew.kt
and
app/src/test/java/com/unittestsample/app/presentation/user/RandomUserViewModelUnitTestOld.kt
You might be wondering why I have created two classes here? No need to worry, I have created two classes just to explain the old method of unit testing and a new approach which is also known as Kotlin style of unit testing. I recommend if you are writing new test cases follow the approach which is written in RandomUserViewModelUnitTestNew.kt
Step 3: Mock the dependencies
Now we have a class where we can write a test case. Here in our RandomUserViewModel has one method fetchRandomUsers() which needs to be unit tested.
To start writing a unit test of our ViewModel we need an object of RandomUserViewModel and it needs RandomUserUseCase instance as an argument in its constructor.
So here we will create a mock object of RandomUserUseCase which helps us to create an object of RandomUserViewModel.
In addition to that, we have an observer which observers the events published by our live data, so we need a mock object of our observer too. And we also need some predefined values which we can expect as output when our unit test finishes its execution.
//output value
private val successLoginResponse: Resource<ArrayList<User>> = Resource(Status.SUCCESS, randomUserResponse().data) private val errorLoginResponse: Resource<Throwable> = Resource(Status.ERROR, throwable = Exception()) //mock dependencies
private val randomUserUseCase = mock<RandomUserUseCase>() private val randomUserViewModel by lazy { RandomUserViewModel(randomUserUseCase) } private var randomUserObserver = mock<Observer<Resource<ArrayList<User>>>>()
Step 4: Stubbing
Now, we have a method to test, which gets the data from an asynchronous data source (here web API).
For a quick note unit tests never performs an actual data fetching, so we have to provide the data when any asynchronous operation takes place, this is called stubbing.
Here we will provide a dummy response when our API will get a call from our unit test. We will test two scenarios, success and failure so we have written two stubbings which can be used for different scenarios.
private fun stubFetchRandomUserSuccess() {
whenever(
randomUserUseCase.execute()
).thenReturn(
Single.just(randomUserResponse())
)
} private fun stubFetchRandomUserError() {
whenever(
randomUserUseCase.execute()
).thenReturn(
Single.error(Throwable())
)
}
Step 5: Execution
As a final step, we will write the test case itself. Set an observer first on the live data object and execute the method that we want to test. In our case fetchRandomUsers() is a private method which is called inside loadPage() so we will call loadPage() method in order to test our actual method.
Now we will observe the response and if it matched with our expected response that our case is tested successfully.
Here I have added success and failure cases, it may need more cases to be tested as per different scenarios.
That’s it for now, feel free to share your review and let us know if you need separate series on Dagger2 in comments below.