Юнит-тестирование сопрограмм Kotlin с runBlocking не ждет выполнения
Есть ли какой-нибудь способ дождаться приостановки функции, которая выполняется в области, например, что делает runBlocking для запуска функций приостановки?
Например,
class CoroutineTestCase : CoroutineScope {
val job = Job()
var value = 1
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Unconfined
fun testFunction() {
async {
delay(2000)
value = 2
}
}
}
@Test
fun testCoroutine() = runBlocking {
val coroutineTestCase = CoroutineTestCase()
coroutineTestCase.testFunction()
assertEquals(2, coroutineTestCase.value)
}
Вышеприведенный тест завершается неудачно со значением 1 и не изменяется (так как launch
не ожидал, чтобы закончить). Если testFunction
была приостановка функции, и я запустил ее с runBlocking внутри моего модульного теста, все бы работало.
Я пробовал с другими пользовательскими диспетчерами (такими как приведенный ниже), которые могут блокировать выполнение своих задач, но не повезло
class TestUiContext : CoroutineDispatcher() {
override fun dispatch(context: CoroutineContext, block: Runnable) {
block.run()
}
}
1 ответ
Хорошо, я понял, что происходит. Запуск не ожидается, поскольку его возвращаемое значение никогда не используется.
В приведенном выше примере testFunction
должен вернуть возвращаемое значение launch, которое является Deffered объектом, который можно ожидать / присоединяться. Таким образом, чтобы фактически дождаться его завершения, необходимо изменить код, как показано ниже:
class CoroutineTestCase : CoroutineScope {
val job = Job()
var value = 1
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Unconfined
fun testFunction(): Deferred<Unit> {
return async {
delay(20000)
value = 2
}
}
}
@Test
fun testCoroutine() = runBlocking {
val coroutineTestCase = CoroutineTestCase()
coroutineTestCase.testFunction().await()
assertEquals(2, coroutineTestCase.value)
}
В настоящее время единственная проблема заключается в том, что в этом случае она фактически задерживается на 20 секунд (с неограниченным диспетчером).