Sala de pruebas de unidad y LiveData
Actualmente estoy desarrollando una aplicación con los nuevos componentes de arquitectura de Android . En concreto, estoy implementando una base de datos de sala que devuelve un objeto LiveData
en una de sus consultas. La inserción y la consulta funcionan como se esperaba, sin embargo, tengo un problema probando el método de consulta usando la prueba de unidad.
Aquí está el DAO que intento probar:
- Android Studio: No se puede escribir en Preferencias compartidas en la prueba instrumentada
- Agregue ID de programación a R.id
- Cómo corregir la excepción de permiso INJECT_EVENT al enviar toques a una prueba de ActivityInstrumentationTestCase2
- Deshabilitar el error de clase duplicado para las clases en la carpeta de prueba - Android Studio / IntelliJ
- Autogenerar stubs de prueba de unidad en Android studio
NotificationDao.kt
@Dao interface NotificationDao { @Insert fun insertNotifications(vararg notifications: Notification): List<Long> @Query("SELECT * FROM notifications") fun getNotifications(): LiveData<List<Notification>>
}
Como se puede ver, la función de consulta devuelve un objeto LiveData
, si cambio esto para ser sólo una List
, un Cursor
o básicamente lo que sea, entonces obtengo el resultado esperado, que es el dato insertado en la base de datos.
El problema es que la prueba siguiente siempre fallará porque el value
del objeto LiveData
siempre es null
:
NotificationDaoTest.kt
lateinit var db: SosafeDatabase lateinit var notificationDao: NotificationDao @Before fun setUp() { val context = InstrumentationRegistry.getTargetContext() db = Room.inMemoryDatabaseBuilder(context, SosafeDatabase::class.java).build() notificationDao = db.notificationDao() } @After @Throws(IOException::class) fun tearDown() { db.close() } @Test fun getNotifications_IfNotificationsInserted_ReturnsAListOfNotifications() { val NUMBER_OF_NOTIFICATIONS = 5 val notifications = Array(NUMBER_OF_NOTIFICATIONS, { i -> createTestNotification(i) }) notificationDao.insertNotifications(*notifications) val liveData = notificationDao.getNotifications() val queriedNotifications = liveData.value if (queriedNotifications != null) { assertEquals(queriedNotifications.size, NUMBER_OF_NOTIFICATIONS) } else { fail() } } private fun createTestNotification(id: Int): Notification { //method omitted for brevity }
Así que la pregunta es: ¿Alguien sabe de una mejor manera de realizar pruebas de unidad que implican objetos LiveData?
- Android Testing: ¿Puedo enviar sms al número de emulador del método de prueba?
- ¿Ejecutar pruebas de unidad android desde la línea de comandos?
- Crear proyecto de prueba de android en intellij idea 13 community edition
- Prueba de unidad de ciclo de vida de actividad
- Prueba de clases sin actividad en Android
- Prueba de unidad Android SMS Receiver
- Cómo determinar la unidad de píxeles (px, dp, etc) de una vista en Java?
- ¿Por qué realizar pruebas en un proyecto separado, en lugar de carpeta?
Room calcula el valor de LiveData
perezosamente cuando hay un observador.
Puede comprobar la aplicación de ejemplo .
Utiliza un método de utilidad getValue que agrega un observador para obtener el valor:
public static <T> T getValue(final LiveData<T> liveData) throws InterruptedException { final Object[] data = new Object[1]; final CountDownLatch latch = new CountDownLatch(1); Observer<T> observer = new Observer<T>() { @Override public void onChanged(@Nullable T o) { data[0] = o; latch.countDown(); liveData.removeObserver(this); } }; liveData.observeForever(observer); latch.await(2, TimeUnit.SECONDS); //noinspection unchecked return (T) data[0]; }
Mejor w / kotlin, usted puede hacer una función de extensiones :).
Cuando devuelve un LiveData
de un Dao
en el Cuarto hace que la consulta sea asíncrona, y como @yigit dice que Room establece el LiveData#value
perezosamente después de iniciar la consulta observando el LiveData
. Este patrón es reactivo .
Para las pruebas de unidad que desea que el comportamiento sea síncrono, por lo que debe bloquear el hilo de prueba y esperar a que el valor que se pasa al observador, a continuación, tomar de allí y entonces usted puede afirmar en él.
Esta es una función de extensión de Kotlin para hacer esto:
fun <T> LiveData<T>.blockingObserve(): T? { var value: T? = null val latch = CountDownLatch(1) val innerObserver = Observer<T> { value = it latch.countDown() } observeForever(innerObserver) latch.await(2, TimeUnit.SECONDS) return value }
Puedes usarlo así:
val someValue = someDao.getSomeLiveData().blockingObserve()
- Cómo reactivar una advertencia de Android Lint deshabilitada en el nivel de archivo
- Android: la foto tomada es más grande que la vista previa