Reputation: 305
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
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
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