SamCosta1
SamCosta1

Reputation: 305

Testing involving MutableSharedFlow - java.lang.IllegalStateException: This job has not completed yet

Apologies for what is probably a very amateur question. I'm getting to grips with flows and having issues with testing where MutableSharedFlow is concerned.

The following is the simplest example I can construct that recreates the problem:

@ExperimentalCoroutinesApi
@ExperimentalTime
class MyExampleTest {

    val testDispatcher: TestCoroutineDispatcher = TestCoroutineDispatcher()

    @Test
    fun test() = testDispatcher.runBlockingTest  {
        val sharedFlow = MutableSharedFlow<String>()

        sharedFlow.take(2).collect {
            println(it)
        }

        sharedFlow.tryEmit("Hello")
        sharedFlow.tryEmit("World")
    }
}

This results int he following error:

java.lang.IllegalStateException: This job has not completed yet

    at kotlinx.coroutines.JobSupport.getCompletionExceptionOrNull(JobSupport.kt:1187)
    at kotlinx.coroutines.test.TestBuildersKt.runBlockingTest(TestBuilders.kt:53)
    at kotlinx.coroutines.test.TestBuildersKt.runBlockingTest(TestBuilders.kt:80)
    at com.example.MyExampleTest.test(MyExampleTest.kt:22)

From my limited understanding I think it's something to do with the fact that SharedFlow never completes. But I thought having the take(2) would mitigate this. Any suggestions would be appreciated!

Upvotes: 4

Views: 1778

Answers (2)

Cristian P.
Cristian P.

Reputation: 238

Inside tests use runBlocking instead of runBlockingTest.

For flow testing combine it with a launch from scope. E.g:

val testDispatcher = TestCoroutineDispatcher()
val testScope = TestCoroutineScope(testDispatcher)

   runBlocking {
        val job1 = testScope.launch {
            doJobThatNeedsCollect(Unit).collect {
                when (it) {
                    is Success -> {
                        isSuccess = true
                        cancel()
                    }
                    is Failure -> {
                        isSuccess = false
                        cancel()
                    }
                }
            }
        }
        while (!job1.isCancelled) {
        }
        assertTrue(isSuccess)
    }

Upvotes: 0

shredder
shredder

Reputation: 1457

From my limited understanding I think it's something to do with the fact that SharedFlow never completes.

You're right, this is more or less the problem. Flow is based on Coroutines and the coroutine has not completed.

The best way to unit test Flows in my opinion is Turbine:

https://github.com/cashapp/turbine

// Cold Flow
flowOf("one", "two").test {
  assertEquals("one", expectItem())
  assertEquals("two", expectItem())
  expectComplete()
}

// Hot Flow
MutableStateFlow("test").test {
    assertThat(expectItem()).isEqualTo("test")
    cancelAndConsumeRemainingEvents()
}

There is also an open issue about this exact "problem":

https://github.com/Kotlin/kotlinx.coroutines/issues/1204

Upvotes: 2

Related Questions