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() 
  • No se pueden usar los nombres de método retrocedidos de Kotlin en androidTest - exception de descriptor incorrecto
  • Ejecute testings de Kotlin Koans desde Android Studio
  • Kotlin coroutines unit testing usando mockito
  • Unidad de testing Room y LiveData
  • Kotlin Unit Test siempre pasa cuando se ejecuta desde la IU de Android Studio
  • La cobertura de código de estudio de Android no muestra ninguna class de Kotlin
  • Referencia no resuelta: DaggerTestComponent (Kotlin with Dagger for Test)
  • ¿Cómo probar una class con un oyente anónimo que se establece dentro de una function?
  • La testing Running Spek muestra el error "Suite de testing vacía"
  • Prueba unitaria de la function de extensión de Kotlin en las classs de Android SDK
  • El resultado es el mismo, pero el caso de testing no pasa en la testing unitaria