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() 
  • ¿Cómo probar el método del presentador en base a un valor devuelto por Observable?
  • Unidad de testing Room y LiveData
  • Kotlin Unit Test siempre pasa cuando se ejecuta desde la IU de Android Studio
  • Kotlin coroutines unit testing usando mockito
  • Solo la primera testing pasa con TestScheduler cuando se ejecutan varias testings (Kotlin)
  • Calculadora simple, testing unitaria usando KOTLIN con Spek (código de salida -1)
  • La testing Running Spek muestra el error "Suite de testing vacía"
  • Comparta el código entre la testing unitaria y las testings de instrumentación cuando use kotlin
  • Referencia no resuelta: DaggerTestComponent (Kotlin with Dagger for Test)
  • La cobertura de código de estudio de Android no muestra ninguna class de Kotlin
  • ¿Cómo no emitir datos de Flowable para testings unitarias?