如何测试Kotlin协程actors

4

我已经按照官方的kotlinx.coroutines文档实现了一个Actor。现在我需要在我的仪器测试中对它们进行测试,但我总是得到:

IllegalStateException: This job has not completed yet

这是我的测试代码:

@RunWith(AndroidJUnit4::class)
@ExperimentalCoroutinesApi
class ExampleInstrumentedTest {

    @Test
    fun testIncrease() = runBlockingTest {
        val counter = Counter()
        for (i in 0..10) {
            counter.increase()
        }
    }

    @Test
    fun testException() = runBlockingTest {
        val counter = Counter()
        try {
            for (i in 0..11) {
                counter.increase()
            }
            Assert.fail()
        } catch (e: Exception) {
            // All good if the exception was thrown
        }
    }
}

这里是演员:

sealed class CounterMsg
object IncCounter : CounterMsg()
class GetCounter(val response: CompletableDeferred<Int>) : CounterMsg()

class CounterActor {
    private val actor = GlobalScope.actor<CounterMsg> {
        var counter = 0
        for (msg in channel) {
            when (msg) {
                is IncCounter -> if (counter < 10) counter++ else throw RuntimeException()
                is GetCounter -> msg.response.complete(counter)
            }
        }
    }

    suspend fun send(message: CounterMsg) = actor.send(message)
}

class Counter {
    private val actor = CounterActor()
    suspend fun increase() = actor.send(IncCounter)
}

我的依赖项:

implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.40"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.3.0-M1"
androidTestImplementation "androidx.test.ext:junit:1.1.1"
androidTestImplementation "androidx.test:runner:1.2.0"
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:1.3.40"
androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.0-M1"

我已经尝试过GlobalScope.actor<CounterMsg>(Dispatchers.Unconfined),至少能让第一个测试变为绿色,但异常测试仍然失败。


可能与 https://github.com/Kotlin/kotlinx.coroutines/issues/1204 有关。 - mbo
2个回答

0

显然,只需进行一些小的更改即可使其正常工作:

  • 在actor中使用cancel()而不是抛出异常
  • 使用runBlocking而不是runBlockingTest

1
runBlocking 不会像 runBlockingTest 一样导致测试失败,因此您的测试始终都会成功。 - HotJard

0

我通过添加下列规则解决了这个问题:

@get: Rule
var instantExecutorRule = InstantTaskExecutorRule()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接