Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Kotlin流:测试挂起_Kotlin_Kotlin Coroutines_Kotlin Flow_Kotlin Coroutines Flow_Kotest - Fatal编程技术网

Kotlin流:测试挂起

Kotlin流:测试挂起,kotlin,kotlin-coroutines,kotlin-flow,kotlin-coroutines-flow,kotest,Kotlin,Kotlin Coroutines,Kotlin Flow,Kotlin Coroutines Flow,Kotest,我正在尝试使用流测试Kotlin实现。我使用Kotest进行测试。此代码适用于: 视图模型: val detectedFlow = flow<String> { emit("123") delay(10L) emit("123") } 但是,在real ViewModel中,我需要向流中添加值,因此我使用ConflatedBroadcastChannel,如下所示: private val _detectedValues = ConflatedBroadca

我正在尝试使用流测试Kotlin实现。我使用Kotest进行测试。此代码适用于:

视图模型:

val detectedFlow = flow<String> {
    emit("123")
    delay(10L)
    emit("123")
}
但是,在real ViewModel中,我需要向流中添加值,因此我使用
ConflatedBroadcastChannel
,如下所示:

private val _detectedValues = ConflatedBroadcastChannel<String>()
val detectedFlow = _detectedValues.asFlow()

suspend fun sendDetectedValue(detectedString: String) {
    _detectedValues.send(detectedString)
}
测试只是挂起,永远不会完成。我尝试了各种方法:
launch
runBlockingTest
而不是
runBlockingTest
,将发送和收集放在相同或单独的协同程序中,
offer
而不是
send
。。。似乎没有什么能解决它。我做错了什么

更新:如果我手动创建流,它会工作:

private val _detectedValues = ConflatedBroadcastChannel<String>()
val detectedFlow =  flow {
    this.emit(_detectedValues.openSubscription().receive())
}
private val_detectedValues=confollatedbroadcastchannel()
val detectedFlow=流量{
this.emit(_detectedValues.openSubscription().receive())
}
那么,它是
asFlow()
方法中的一个bug吗?

问题是,您在测试中使用的函数是一个挂起函数,它将挂起执行,直到
完成

在第一个示例中,您的
detectedFlow
是有限的。它只会发出两个值并完成。在您的问题更新中,您还创建了一个有限流,它将发出一个值并完成。这就是为什么你的测试有效

但是,在第二个(现实生活)示例中,流是从从不关闭的
合并DBRoadCastChannel
创建的。因此,
collect
函数将永远暂停执行。要使测试在不永久阻塞线程的情况下工作,还需要使流有限。对此,我通常使用
first()
操作符。另一个选项是
关闭
合并的dbroadcast频道
,但这通常意味着仅仅因为测试不是一个好的实践,就要修改代码

这就是测试如何使用
first()
操作符

"when the flow contains values they are emitted" {
    val detectedString = "123"
    val vm = ScanViewModel()
    runBlocking {
        vm.sendDetectedValue(detectedString)
    }
    runBlocking {
        vm.detectedFlow.first() shouldBe detectedString
    }
}

你试过在其他调度器上启动吗,只是为了调试?是的。没有效果。顺便说一句,我尝试了新发布的StateFlow/MutableStateFlow,但问题仍然存在,如果我们的整个测试函数被标记为
runBlocking
?@IgorGanapolsky,我相信在这种情况下整个测试函数也会挂起。我们如何处理生产代码在流和通道上使用
collect
的情况?@TomášHavlíček
collect
不会挂起,因为它是异步的
private val _detectedValues = ConflatedBroadcastChannel<String>()
val detectedFlow =  flow {
    this.emit(_detectedValues.openSubscription().receive())
}
"when the flow contains values they are emitted" {
    val detectedString = "123"
    val vm = ScanViewModel()
    runBlocking {
        vm.sendDetectedValue(detectedString)
    }
    runBlocking {
        vm.detectedFlow.first() shouldBe detectedString
    }
}