如何使用 runBlocking 等待 CoroutineScope 的完成

How to use runBlocking to await the completion of a CoroutineScope

我正在尝试测试一个将自己声明为 CoroutineScope 的 class。 class 有一些方法在其范围内 launch 作业,我必须从测试方法断言这些作业的效果。

这是我尝试过的:

import kotlinx.coroutines.*

class Main : CoroutineScope {
    override val coroutineContext get() = Job()

    var value = 0

    fun updateValue() {
        this.launch {
            delay(1000)
            value = 1
        }
    }
}

fun main() {
    val main = Main()
    val mainJob = main.coroutineContext[Job]!!
    main.updateValue()
    runBlocking {
        mainJob.children.forEach { it.join() }
    }
    require(main.value == 1)
}

我的期望是 updateValue() 将在 coroutineContext 中创建根作业的子项。但事实证明 mainJob.children 是空的,所以我不能等待 launch 完成并且 require 语句失败。

完成这项工作的正确方法是什么?

将协程构建器启动修改为

this.launch(start = CoroutineStart.LAZY) 

并将您的工作对象初始化更改为直接

override val coroutineContext : Job =   Job()  

它应该会产生预期的结果

这是我试过的例子,它产生了想要的结果

import kotlinx.coroutines.*
import kotlin.coroutines.CoroutineContext

class Main : CoroutineScope {

val scope: CoroutineScope = this

override val coroutineContext = Job()
    //Dispatchers.Default +

var value = 0

 fun updateValue(csc : CoroutineScope) {
    csc.launch(context = coroutineContext, start = CoroutineStart.LAZY) { println(this.coroutineContext[Job]!!.toString() + " job 2") }
    csc.launch (context = coroutineContext, start = CoroutineStart.LAZY){ println(this.coroutineContext[Job]!!.toString() + " job 3") }
    csc.launch (start = CoroutineStart.LAZY){
        println(this.coroutineContext[Job]!!.toString() + " job 1")
        //delay(1000)
        value = 1
    }

 }

fun something() {
    launch (start = CoroutineStart.LAZY){
        println(this.coroutineContext[Job]!!.toString() + " something 1")
    }

    launch (start = CoroutineStart.LAZY){
        println(this.coroutineContext[Job]!!.toString() + " something 2")
    }

    launch(start = CoroutineStart.LAZY) {
        println(this.coroutineContext[Job]!!.toString() + " something 3")
        delay(2000)
        value = 1
    }
}

}

fun main() {
    val main = Main()
    val mainJob = main.coroutineContext[Job]!!
    main.updateValue(main.scope)
    //main.something()
    runBlocking {
        //println(mainJob.children.count())
        println(mainJob.children.count())
        mainJob.children.forEach {
            //println("in run blocking")
            println(it.toString())
            it.join()
        }
    }
    println(main.value)
}


`

我的代码中的错误很简单:

override val coroutineContext get() = Job()

我不小心留下了自定义 getter,这意味着每次访问 coroutineContext 都会创建一个新作业。自然,我在测试代码中得到的工作没有children。删除 get() 使代码工作:

override val coroutineContext = Job()