unit-testing kotlin kotlinx.coroutines

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 .