dimsuz
01/28/2022, 1:04 PMclass Feature {
private val scope = CoroutineScope()
private val _flow = MutableSharedFlow<Int>()
fun start() {
scope.launch { flow.emit(1); flow.emit(2) }
}
val flow: Flow<Int> = _flow
}
test code:
should("do something") {
val awaitFirstEmit = feature.flow.onStart { feature.start() }.first()
awaitFirstEmit shouldBe 1
}
Is it OK to use onStart like this, or will this produce flakiness?
the important thing here is I want to ensure that first item is not lost.Joffrey
01/28/2022, 1:08 PMFeature.flow was exposed as SharedFlow, you could use onSubscription for this, which is meant for that. As for Flow.onStart, I'm not 100% sure there is this guaranteedimsuz
01/28/2022, 1:08 PMdimsuz
01/28/2022, 1:10 PMonSubscription internallyJoffrey
01/28/2022, 1:16 PMonStart is run before the upstream collection begins - effectively calling feature.start() before subscribing to the shared flow.
You can prove it doesn't work by adding an atrifical delay after feature.start() in onStart in your test. It will hang forever if it missed the emissionsJoffrey
01/28/2022, 1:19 PMfirst() you could consider it a guarantee that first is reached by the main coroutine of the test before the emissions are done by the launched coroutine. But it's probably not your case here, since CoroutineScope() likely uses the Default dispatcher. And in any case I would personally not like to rely on that 😄dimsuz
01/28/2022, 1:38 PMDefault by default 🙂 Thank you for suggestions and advice! Will think about how to best handle this!Nick Allen
01/28/2022, 5:56 PMshould("do something") {
val awaitFirstEmit = async { feature.flow.first() }
advanceUntilIdle() //This should guarantee the subscription
feature.start()
//might need another advanceUntilIdle() here but I don't think so
awaitFirstEmit.await() shouldBe 1
}dimsuz
01/29/2022, 3:31 PM