unit testing - Unidad de pruebas de una Koutlin coroutine con retraso.
unit-testing kotlin (2)
Estoy tratando de hacer una prueba unitaria de una Koutlin coroutine que usa delay()
. Para la prueba de la unidad no me importa la delay()
, solo está ralentizando la prueba. Me gustaría ejecutar la prueba de alguna manera que no se retrase cuando se llama a delay()
.
Intenté ejecutar la rutina utilizando un contexto personalizado que delega a CommonPool:
class TestUiContext : CoroutineDispatcher(), Delay {
suspend override fun delay(time: Long, unit: TimeUnit) {
// I''d like it to call this
}
override fun scheduleResumeAfterDelay(time: Long, unit: TimeUnit, continuation: CancellableContinuation<Unit>) {
// but instead it calls this
}
override fun dispatch(context: CoroutineContext, block: Runnable) {
CommonPool.dispatch(context, block)
}
}
Esperaba poder regresar del método de delay()
de mi contexto, pero en su lugar está llamando a mi método scheduleResumeAfterDelay()
, y no sé cómo delegar eso al programador predeterminado.
En kotlinx.coroutines v0.23.0 introdujeron un TestCoroutineContext .
Pro: hace que sea realmente posible probar coroutines con delay
. Puede configurar el reloj virtual de CoroutineContext en un momento determinado y verificar el comportamiento esperado.
Contras: si su código de código no usa delay
, y solo quiere que se ejecute de forma sincrónica en el hilo de llamada, es un poco más incómodo de usar que el TestUiContext
de la respuesta de @ bj0 (debe llamar a triggerActions()
en el TestCoroutineContext conseguir que la coroutine se ejecute).
Si no desea ningún retraso, ¿por qué simplemente no reanuda la continuación en la llamada programada ?:
class TestUiContext : CoroutineDispatcher(), Delay {
override fun scheduleResumeAfterDelay(time: Long, unit: TimeUnit, continuation: CancellableContinuation<Unit>) {
continuation.resume(Unit)
}
override fun dispatch(context: CoroutineContext, block: Runnable) {
//CommonPool.dispatch(context, block) // dispatch on CommonPool
block.run() // dispatch on calling thread
}
}
De esa manera, el delay()
se reanudará sin demora. Tenga en cuenta que esto todavía se suspende con retraso, por lo que otras coroutinas aún pueden ejecutarse (como el yield()
)
@Test
fun `test with delay`() {
runBlocking(TestUiContext()) {
launch { println("launched") }
println("start")
delay(5000)
println("stop")
}
}
Se ejecuta sin demora y se imprime:
start
launched
stop
EDITAR:
Puede controlar dónde se ejecuta la continuación personalizando la función de dispatch
.