Creación de reglas personalizadas para testear ViewModels con coroutinas
Clase 9 de 16 • Curso de Android Testing
Resumen
Testear ViewModels que utilizan coroutinas puede volverse repetitivo al configurar manualmente dispatchers en cada test. Crear una regla personalizada usando la clase TestWatcher
de JUnit permite encapsular esta lógica repetitiva. Así, se genera un código más limpio, reutilizable y menos susceptible a errores en pruebas.
¿Por qué utilizar TestWatcher para testear coroutinas?
La clase TestWatcher
de la librería JUnit identifica dos escenarios clave: el inicio y el fin de cada test. Al extenderla, se simplifica notablemente la configuración de coroutinas en los tests, automatizando acciones antes y después de su ejecución. Esto evita configurar manualmente Dispatchers.setMain()
y Dispatchers.resetMain()
.
¿Cómo crear una regla personalizada para testear coroutinas?
Para crear nuestra propia regla, seguimos estos pasos:
- Creamos una clase llamada
MainDispatcherRule
dentro del folderutils
. - Extendemos de la clase
TestWatcher
. - Definimos el dispatcher por defecto como
UnconfinedTestDispatcher()
. - Sobrescribimos métodos específicos:
- Método
starting
: llamado al inicio del test; configura el main dispatcher utilizandoDispatchers.setMain()
con nuestro dispatcher definido. - Método
finished
: llamado al finalizar el test; restablece dispatcher principal medianteDispatchers.resetMain()
.
La clase en Kotlin se ve así:
@ExperimentalCoroutinesApi
class MainDispatcherRule(
val testDispatcher: TestDispatcher = UnconfinedTestDispatcher()
) : TestWatcher() {
override fun starting(description: Description?) {
Dispatchers.setMain(testDispatcher)
}
override fun finished(description: Description?) {
Dispatchers.resetMain()
}
}
¿Cómo implementar esta regla en nuestros tests de ViewModel?
Al integrar la regla creada en nuestros tests:
- Removemos configuraciones repetitivas y minimizamos la posibilidad de olvidar restablecer el dispatcher.
- Reemplazamos las acciones manuales por nuestra regla, declarándola simplemente con
@get:Rule
. - Eliminamos llamados repetitivos a métodos como
advanceUntilIdle()
a menos que se utilicen dispatchers específicos que requieran su uso explícito.
Esto es cómo se vería su implementación:
@get:Rule
val mainDispatcherRule = MainDispatcherRule()
Al ejecutar los tests con esta nueva regla:
- Si utilizamos
UnconfinedTestDispatcher()
, no necesitamos llamar aadvanceUntilIdle()
. - Si utilizamos
StandardTestDispatcher()
, debemos añadir de nuevoadvanceUntilIdle()
para que los tests pasen.
La personalización de esta regla aporta facilidad y efectividad al testeo de ViewModels con coroutinas.