Corutinas de testing unitaria en el hilo de UI

Estoy usando corutinas para hacer una llamada asincrónica en pull para actualizar así:

class DataFragment : Fragment(), SwipeRefreshLayout.OnRefreshListener { // other functions here override fun onRefresh() { loadDataAsync() } private fun loadDataAsync() = async(UI) { swipeRefreshLayout?.isRefreshing = true progressLayout?.showContent() val data = async(CommonPool) { service?.getData() // suspending function }.await() when { data == null -> showError() data.isEmpty() -> progressLayout?.showEmpty(null, parentActivity?.getString(R.string.no_data), null) else -> { dataAdapter?.updateData(data) dataAdapter?.notifyDataSetChanged() progressLayout?.showContent() } } swipeRefreshLayout?.isRefreshing = false } } 

Todo aquí funciona bien cuando realmente lo pongo en un dispositivo. Mis estados de error, vacío y datos se manejan bien y el performance es bueno. Sin embargo, también estoy intentando probarlo con Spek. Mi testing de Spek se ve así:

 @RunWith(JUnitPlatform::class) class DataFragmentTest : Spek({ describe("The DataFragment") { var uut: DataFragment? = null beforeEachTest { uut = DataFragment() } // test other functions describe("when onRefresh") { beforeEachTest { uut?.swipeRefreshLayout = mock() uut?.onRefresh() } it("sets swipeRefreshLayout.isRefreshing to true") { verify(uut?.swipeRefreshLayout)?.isRefreshing = true // says no interaction with mock } } } } 

La testing está fallando porque dice que no hubo interacción con el uut?.swipeRefreshLayout simulacro. Después de un poco de experimentación, parece que esto se debe a que estoy usando el context de la interfaz de usuario a través de async(UI) . Si lo hago simplemente como una synchronization asincrónica, puedo hacer que la testing pase, pero luego la aplicación falla porque estoy modificando las vistas fuera del subprocess de la interfaz de usuario.

¿Alguna idea de por qué esto podría estar ocurriendo? Además, si alguien tiene mejores sugerencias para hacer esto que lo hará más comprobable, soy todo oídos.

Gracias.

EDIT: ¿Olvidé mencionar que también intenté ajustar la verify y el uut?.onRefresh() en un runBlocking , pero aún así no tuve éxito.

Si desea hacer las cosas más claras y considerar el uso de la architecture MVP en el futuro, debe comprender que CourutineContext es una dependencia externa, que se debe inyectar a través de DI, o se debe pasar a su presentador. Más detalles sobre el tema .

La respuesta a su pregunta es simple, solo debe usar CourutineContext no confinado para sus testings. ( más ) Para simplificar las cosas, crea un object, por ejemplo, inyección con:

 package com.example object Injection { val uiContext : CourutineContext = UI val bgContext : CourutineContext = CommonPool } 

y en el package de testing crea absolutamente el mismo object, pero cámbialo a:

 package com.example object Injection { val uiContext : CourutineContext = Unconfined val bgContext : CourutineContext = Unconfined } 

y dentro de tu class será algo así como:

 val data = async(Injection.bgContext) {service?.getData()}.await() 
  • Kotlin coroutines usa produce y mockito para burlarse del trabajo de producción
  • Comparta el código entre la testing unitaria y las testings de instrumentación cuando use kotlin
  • Kotlin coroutines unit testing usando mockito
  • ¿Cómo probar el método del presentador en base a un valor devuelto por Observable?
  • ¿Cómo un código de testing unitaria envuelto en `runOnUiThread`?
  • No se pueden usar los nombres de método retrocedidos de Kotlin en androidTest - exception de descriptor incorrecto
  • cómo acceder a las properties internas desde el código de testing java
  • Solo la primera testing pasa con TestScheduler cuando se ejecutan varias testings (Kotlin)
  • ¿Cómo no emitir datos de Flowable para testings unitarias?
  • Unidad de testing Room y LiveData
  • Calculadora simple, testing unitaria usando KOTLIN con Spek (código de salida -1)