# [Part 1] Testing Coroutines and Kotlin Flows

Testing coroutines in Kotlin can be tricky. Tests need to be setup correctly to avoid flakyness.

In this tutorial you will learn how to write tests for coroutines. We will use an Android project however, the concepts can be applied to any Kotlin based project.

If you are not familiar with unit testing with JUnit or Kotlin Coroutines you can read about it [here](https://developer.android.com/training/testing/unit-testing) & [here](https://kotlinlang.org/docs/coroutines-overview.html).

## Starter Project

Clone the `start` branch of this git repository [https://github.com/shounakmulay/KotlinFlowTest](https://github.com/shounakmulay/KotlinFlowTest).

Open the project in Android Studio. The starter project is based on the [MVVM architecture](https://medium.com/upday-devs/android-architecture-patterns-part-3-model-view-viewmodel-e7eeee76b73b) but without the service layer. It already contains a repository, a view model, and a test class for the view model. 

We will be testing the view model. The repository is just a place holder dependency of the view model. We will mock this repository in our tests.

## Running the first test

The starter project already contains one test. Open the `MainViewModelTest.kt` file in the `app/test` directory.

```kotlin
@Test
fun `Given suspendingFunction is called, When no error occurs, Then repositorySuspendingFunction should be invoked successfully`() = runBlocking {
    mainViewModel.suspendingFunction()

    verify(mainRepository, times(1)).repositorySuspendingFunction()
}
```

- Let's run this test. You can do that by pressing the icon in the gutter right next to the test function name.

![Screenshot_2021-10-13_at_7.29.26_PM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637388477384/0miO5RAPo.png)
- Here we are testing a suspending function in the view model that calls another suspend function in the repository.

```kotlin
suspend fun suspendingFunction() {
    mainRepository.repositorySuspendingFunction()
}
```

- On running this test it should pass as expected.

![Screenshot_2021-10-13_at_7.57.15_PM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637388515860/xTzB0qbxn.png)

The test uses `runBlocking`. It allows us to call suspend functions within its body by creating a new coroutine and blocks the current thread until it completes. This is the behaviour that we want in a test, we do not want any other code running on the thread while the test is in progress.

If the function under test has any calls to `delay` , we can use `runBlockingTest` instead. It works the same as `runBlocking` with a few differences. While `runBlocking` will wait for the amount of the `delay` , `runBlockingTest` will skip past any delay blocks present and will instantly enter the coroutine blocks. This makes the tests run fast and in a more predictable manner.

## Testing functions that launch a new coroutine

Now let's write a test for another function in the view model that calls the same function in the repository, but does that by launching a new coroutine, instead of being a suspend function itself.

```kotlin
fun launchASuspendFunction() = viewModelScope.launch {
    mainRepository.repositorySuspendingFunction()
}
```

- Go to the `MainViewModelTest` file and add a new test that tests `launchASuspendFunction`.

```kotlin
@Test
fun `Given launchASuspendFunction is called, When no error occurs, Then repositorySuspendingFunction should be invoked successfully`() = runBlocking {
    mainViewModel.launchASuspendFunction()

    verify(mainRepository, times(1)).repositorySuspendingFunction()
}
```

- On running this test, it fails with the error message `Module with the Main dispatcher had failed to initialize. For tests Dispatchers.setMain from kotlinx-coroutines-test module can be used`.

![Screenshot_2021-10-13_at_8.02.00_PM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637388589622/13v_2FV0W.png)

- The error means that it was not possible to launch a coroutine on the main thread.
    
    Since `launcASuspendFunction` launches a new coroutine on the `viewModelScope` without any dispatcher provided as an argument, it uses `Dispatchers.Main` by default. In the test environment `Looper.getMainLooper()` is not available thus the test fails.
    
    To solve this issue we need to use `TestCoroutineDispatcher` which executes tasks immediately. 
    
- Set the `TestCoroutineDispatcher` as the main dispatcher in the `setUp` function that executes before every test.

```kotlin
@Before
fun setUp() {
    mainRepository = mock()
    Dispatchers.setMain(TestCoroutineDispatcher())
    mainViewModel = MainViewModel(mainRepository)
}
```

- Create a function that will run after every test to clean up.

```kotlin
@After
fun cleanup() {
    Dispatchers.resetMain()
}
```

- Now if you run the test, because we replaced the main dispatcher, it passes as expected!

![Screenshot_2021-10-13_at_7.57.15_PM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637388628370/N0637LZYO.png)

## Always Inject Dispatchers

Now that we have fixed the problem of `Dispatchers.Main`, let's try some other dispatchers. 

Go to the `MainViewModel` and update the `viewModelScope.launch` method on `launchASuspendFunction` to accept a dispatcher. Let's use the `Default` dispatchers.

```kotlin
fun launchASuspendFunction() = viewModelScope.launch(Dispatchers.Default) {
    mainRepository.repositorySuspendingFunction()
}
```

Run the test again and you will see that it still passes.

So everything is fine right? Not quite.

We could have functions that do more than just one operation or function call. 

- Let's call the repository function one more time.

```kotlin
fun launchASuspendFunction() = viewModelScope.launch(Dispatchers.Default) {
    mainRepository.repositorySuspendingFunction()
    mainRepository.repositorySuspendingFunction()
}
```

- And also update the test to expect 2 calls to `repositorySuspendingFunction`

```kotlin
@Test
fun `Given launchASuspendFunction is called, When no error occurs, Then repositorySuspendingFunction should be invoked successfully`() = runBlocking {
    mainViewModel.launchASuspendFunction()

    verify(mainRepository, times(2)).repositorySuspendingFunction()
}
```

- Now if you run the test, it fails!
We expected the function to be called twice, but it was only called once.

![Screenshot_2021-10-13_at_8.11.36_PM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637388801107/yC9L7NSKs.png)

We replaced the `Main` dispatcher with the `TestCoroutineDispatcer`. But now the function under test is launching a new coroutine on the `Default` dispatcher. To make the test run correctly we need to replace the `Default` dispatcher with `TestCoroutineDispatcher` as well. But there is no method like `Dispatchers.setMain` to replace the `Default` or `IO` dispatcher.


The solution to this is to **inject dispatchers as a dependency** into ****the classes that use them.

- Create a class `CoroutineDispatcherProvider`

```kotlin
data class CoroutineDispatcherProvider(
  val main: CoroutineDispatcher = Dispatchers.Main,
  val default: CoroutineDispatcher = Dispatchers.Default,
  val io: CoroutineDispatcher = Dispatchers.IO
)
```

- Add `CoroutineDispatcherProvider` as a dependency to `MainViewModel`

```kotlin
class MainViewModel(
  private val mainRepository: MainRepository,
  private val dispatcherProvider: CoroutineDispatcherProvider
): ViewModel() {
```

- In `app/di/viewModelModule` update the view model constructor

```kotlin
val viewModelModule = module {
    viewModel { MainViewModel(get(), CoroutineDispatcherProvider()) }
}
```

- Update the `setUp` function of the test class

```kotlin
@Before
fun setUp() {
    mainRepository = mock()
    val testDispatcher = TestCoroutineDispatcher()
    Dispatchers.setMain(TestCoroutineDispatcher())
    val coroutineDispatcherProvider = CoroutineDispatcherProvider(
        main = testDispatcher,
        default = testDispatcher,
        io = testDispatcher
    )
    mainViewModel = MainViewModel(mainRepository, coroutineDispatcherProvider)
}
```

- Finally update the function we are testing to use the dispatcher provider

```kotlin
fun launchASuspendFunction() = viewModelScope.launch(dispatcherProvider.default) {
    mainRepository.repositorySuspendingFunction()
    mainRepository.repositorySuspendingFunction()
}
```

Now if we run the test, it will pass again no matter what dispatcher we use.

## Coroutine Scope Rule

Manually creating a test dispatcher and `CoroutineDispatcherProvider` for every test class is a bit tedious. We can extract this work into a JUnit rule.

- Create a class `CoroutineScopeRule` in the test directory.

```kotlin
@ExperimentalCoroutinesApi
class CoroutineScopeRule(
    private val dispatcher: TestCoroutineDispatcher = TestCoroutineDispatcher(),
    var dispatcherProvider: CoroutineDispatcherProvider = CoroutineDispatcherProvider()
): TestWatcher(), TestCoroutineScope by TestCoroutineScope(dispatcher) {

    override fun starting(description: Description?) {
        super.starting(description)
        Dispatchers.setMain(dispatcher)
        dispatcherProvider = CoroutineDispatcherProvider(
            main = dispatcher,
            default = dispatcher,
            io = dispatcher
        )
    }

    override fun finished(description: Description?) {
        super.finished(description)
        cleanupTestCoroutines()
        Dispatchers.resetMain()
    }
    
}
```

- We can apply this rule as

```kotlin
@get:Rule
val coroutineScope = CoroutineScopeRule()
```

- We can also create a `BaseTest`class that will apply the rule. Create an new file `BaseTest`

```kotlin
open class BaseTest {
    
    @get:Rule
    val coroutineScope = CoroutineScopeRule()
}
```

- And make the `MainViewModelTest` class extend from `BaseTest`

```kotlin
class MainViewModelTest: BaseTest()
```

- We can now get rid of the dispatchers related code in the setup function of `MainViewModelTest`

```kotlin
@Before
fun setUp() {
    mainRepository = mock()
    mainViewModel = MainViewModel(mainRepository, coroutineScope.dispatcherProvider)
}
```

- The `cleanup` function can be deleted as that part is already handled by the rule applied in the `BaseTest` class.

## Where to go from here

You now have a setup that can help you write unit tests that deal with coroutines and any dispatchers!

You can look at the complete code after part 1 at [https://github.com/shounakmulay/KotlinFlowTest/tree/part1-end](https://github.com/shounakmulay/KotlinFlowTest/tree/part1-end)

In Part 2 we will look at testing Kotlin Flows. Here's the link to Part 2
https://blog.shounakmulay.dev/part-2-testing-coroutines-and-kotlin-flows
