Unit testing with Mockk tweaks and tricks part1
Tags: android, mockk, kotlin, testing
Published: 2022-03-09 18:17:17

##Overview
This post is meant to be for some tweaks and tricks in MockK like testing **Private methods** with their return value and **livedata** changes. It's not an introduction to the library. Actually the [documentation ](https://mockk.io/) is great for exploring the library.

## Introduction

**Why should we write code to test an already implemented feature, when we can use that time in implementing another feature ?**

Many developers seem to underestimate the value added by unit and integration test code.

Actually I believe the code written in Software testing is of more value on the long run than that of the production, because as long as project is not dead and is used, there will always be new feature requests and new bugs emerge that needs to be fixed.

How will we make sure that the code added didn't make other issues in the already working features?

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w7g9f9t74et0ie9mxr0x.jpg)
Software testing is needed for the survival of the production code. Manual testing made by us will never be enough to verify that every thing is working fine.

And of course the testing code changes over time, and because of that you have to write your tests in a clean way, to be able to change them easily.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ban6tdgpe17r7q5y58xz.png)
## The importance of Mocking

We use mocking in many cases:

1. mocking the dependencies needed by a class to test it separately as a black box
2. Make our tests run faster by mocking databases or server responses instead of using real ones, and many more.

##Mockk 
MockK is one of the best mocking libraries for Kotlin, it supports coroutines and has many cool features.

No more talk and let's see a practical example.

Here is an example `LoginViewModel` class that we will test through the post
```kotlin
class LoginVM constructor(
    private val loginUseCase: ILoginUseCase,
) {

    fun login(userIdentifier: String, password: String): Boolean {
        return if (isFormValid(userIdentifier, password)) {
            loginValidatedUser(userIdentifier, password)
        } else false
    }


    private fun isFormValid(userIdentifier: String, password: String): Boolean {
        return if (isFieldEmpty(userIdentifier)) {
            false
        } else if (!isInputNumerical(userIdentifier) && !isEmailValid(userIdentifier)) {
            false
        } else if (isInputNumerical(userIdentifier) && !isPhoneNumberValid(userIdentifier)) {
            false
        } else if (isFieldEmpty(password)) {
            false
        } else isPasswordValid(password)
    }

    private fun loginValidatedUser(userIdentifier: String, password: String): Boolean {
        return loginUseCase.login(userIdentifier, password)
    }
}
```

This class has one public method which is `login` that takes `userIdentifier` and `password` and then it checks if they are valid or not and depending on that it will call the `loginUseCase` object.

And that's the ILoginUseCase interface:
```kotlin
interface ILoginUseCase {
    fun login(userIdentifier: String, password: String): Boolean
}
```

To test this class we will need to mock the login use case which is passed in the constructor, first.
And that's how it's done in MockK: 
```kotlin
val loginUseCase = mockk<ILoginUseCase>()
val viewModel = LoginVM(loginUseCase)
```
###Testing a mocked object is not called at all
Now let's call the `login` method in the `LoginVM` with invalid `userIdentifier` and check if the `loginUseCase` is not called at all
```kotlin
val result = viewModel.login("", "")
verify { loginUseCase wasNot Called } //used only to check the whole mocked object
```


###Testing that a method is not called
That's how to see if a specific method is not called at all:
```kotlin
 verify(exactly = 0) {
    loginUseCase.login(any(),any() )
 } //used to detect if a method was not called in the mocked object
```
`any()` is used to represent any argument, if we want to check if the method with a specific argument, we will remove `any()` and pass that value instead.

###Mocking a method
Now if we provided a valid `userIdentifier` and `password` to the login method in the `LoginVM` we will get an exception for not defining the behavior of the `login` method in the use case

So let's make this method return `false` at first and then `true`
and always remember, the last returned value will remain the answer of that method if it's called more than twice.
```kotlin
val loginUseCase = mockk<ILoginUseCase>()
every { loginUseCase.login(any(), any()) } returns false andThen true

val viewModel = LoginVM(loginUseCase)
//return false
var result = viewModel.login("david@gmail.com", "Test@123")
assertEquals(false, result)

 //return true
result = viewModel.login("david@gmail.com", "Test@123")
assertEquals(true, result)
```
###Custom Mocking
We can return a specific response depending on the passed arguments and here's how:
```kotlin
val loginUseCase = mockk<ILoginUseCase>()
every { loginUseCase.login(any(), any()) } answers {
  val email: String = arg(0)
  val password: String = arg(1)
  email == "david@gmail.com" && password == "Test@123"
}
val viewModel = LoginVM(loginUseCase)
assertEquals(true, viewModel.login("david@gmail.com", "Test@123"))
assertEquals(false, viewModel.login("davi@gmail.com", "Test@123"))
assertEquals(false, viewModel.login("david@gmail.com", "Test@23"))
```
###Testing private methods
Even though I don't recommend it, the need to test private methods could be a code smell that you need to refactor the logic inside that method into a separate testable class and leave that method private.
But Yes
We will use `spyk` provided by MockK which is used to create a real object that we can spy on and create some mocked behavior for specific methods of that object. 
Since MockK uses reflection to test the private methods, we will need to pass the method name and the arguments types as shown in the `verify` block.
```kotlin
val viewModel = spyk(LoginVM(loginUseCase), recordPrivateCalls = true)

verify {  viewModel["isFormValid"](any<String>(), any<String>())}
```
###Testing return of private methods:

Sadly the library doesn't support testing the return of private methods in a direct way, but it has many features that we can use them to test this value.

Let's try to test `isFormValid` private method in the view model class.
The idea I came up with is to use `every` block provided by MockK DSL to mock the behavior of that private method and call the actual method in that block using `callOriginal()` provided by MockK to record the return value in a separate value, and return that value in the defined mocking behavior so that nothing differs from the behavior of the original method

```kotlin
val loginUseCase = mockk<ILoginUseCase>()
val viewModel = spyk(LoginVM(loginUseCase), recordPrivateCalls = true)
var returnValue: Boolean? = null
every { viewModel["isFormValid"](any<String>(), any<String>()) } answers {
    returnValue = callOriginal() as Boolean
    return@answers returnValue
}
viewModel.login("david", "123")
assertEquals(false, returnValue!!)
```

###Capturing the arguments passed to a mocked method
We  can always get the passed argument to our mocked method to make some complex test cases. 
Actually I find it an **important** technique that helped me a lot to capture the changes in live data or any observable object.

Let's see example first, we will try to capture the passed email to the login method:
```kotlin
val loginUseCase = mockk<ILoginUseCase>(relaxed = true)
val viewModel = LoginVM(loginUseCase)
val captureEmailArg = mutableListOf<String>()

viewModel.login("david@gmail.com", "Test@123")
viewModel.login("davi@gmail.com", "Test@123")
viewModel.login("dav@gmail.com", "Test@123")

verify {loginUseCase.login(capture(captureEmailArg), any())}
println(captureEmailArg)
```
The printed list is `[david@gmail.com, davi@gmail.com, dav@gmail.com]`

But how to use this to test the changes in a `livedata` and not only the most recent value?
The idea is simple, we will mock an `Observer` object and pass it to the `liveData` object and when this `liveData` changes it will call the `onChanged` method of the observer object passing the new state as an argument, and that's what we need this argument is the new value of the live data that we need to capture similar to the example above
Here's the code for observing a `livedata` that holds a `String` 
```kotlin
val mockedObserver :Observer<String> = mockk(relaxed = true)
val changes = mutableListOf<String>()
every { mockedObserver.onChanged(capture(changes)) }
val liveData = MutableLiveData("")
liveData.observeForever(mockedObserver)
```
 Now the `changes` will contain all the changes happened in the live data.

---
Here is a [repo ](https://github.com/DavidIbrahim/TestingMockk)with most of the code used.


Thanks for reading so far, if you have an extra trick or tip for using this awesome library you can share it with us in the comments ^_^