Отсутствие ценности LiveData при тестировании Room - PullRequest
0 голосов
/ 18 июня 2020

Я пытаюсь протестировать свою базу данных комнаты и наблюдаю за испускаемыми LiveData, используя эту функцию, как рекомендовано в образце компонентов архитектуры приложения GitHub.

Примечание. Я получаю реляционный класс, а не стандартный Entity из таблицы. Объект отношения один-один. Хотя этот вызов работает при запуске приложения на устройстве.

Я знаю, что упускаю здесь какую-то глупую деталь. Было бы здорово, если бы вы могли указать мне на это.

fun <T> LiveData<T>.getOrAwaitValue(
    time: Long = 2,
    timeUnit: TimeUnit = TimeUnit.SECONDS
//    afterObserve: () -> Unit = {}
): T {
    var data: T? = null
    val latch = CountDownLatch(1)
    val observer = object : Observer<T> {
        override fun onChanged(o: T?) {
            data = o
            latch.countDown()
            this@getOrAwaitValue.removeObserver(this)
        }
    }
    this.observeForever(observer)

//    afterObserve.invoke()

    // Don't wait indefinitely if the LiveData is not set.
    if (!latch.await(time, timeUnit)) {
        this.removeObserver(observer)
        throw TimeoutException("LiveData value was never set.")
    }

    @Suppress("UNCHECKED_CAST")
    return data as T
}

Но я получаю сообщение об ошибке, что я не могу получить доступ к данным в фоновом потоке. Я могу решить эту проблему, запустив его в основном потоке с помощью сопрограмм, но LiveData не возвращает значение и остается нулевым, что вызывает исключение TimeOutException.

Это мой тестовый метод

@Test
    //    @Throws(Exception::class)
    fun writeBagAndItemAssociation() = runBlocking {
        var bag1 = BagItem(bagId = 1, bagName = "AT", bagColor = 0)
        var bag2 = BagItem(bagId = 2, bagName = "Kamiliant", bagColor = 0)
        bagItemDao.insert(bag1)
        bagItemDao.insert(bag2)

        bag1 = bagItemDao.findItemsByName(bag1.bagName)[0]
        bag2 = bagItemDao.findItemsByName(bag2.bagName)[0]

        var item = InventoryItem(itemId = 1, itemName = "Blazer", bagOwnerId = bag2.bagId)
        inventoryItemDao.insert(item)
        CoroutineScope(Dispatchers.Main).launch {
            item = inventoryItemDao.findItemsByName("Blazer").getOrAwaitValue()[0]
            assertNotNull(item)
        }

        val itemsInBag2 =
            bagItemDao.getItemsAndBagsInBagWithId(id = bag2.bagId)
        assertEquals(1, itemsInBag2?.items?.size)

        val itemsInBag1 =
            bagItemDao.getItemsAndBagsInBagWithId(id = bag1.bagId)
        assertEquals(0, itemsInBag1?.items?.size)


//        val allItemsWithBag =
//            inventoryItemDao.getItemsWithBag().getOrAwaitValue()
//        assertThat(allItemsWithBag.size, `is`(1))
//        assertEquals(1, allItemsWithBag.size)
    }

ItemInventoryDao.kt

@Dao
interface InventoryItemDao : BaseDao<InventoryItem> {

    /**
     * Selects and returns the row that matches the supplied start time, which is our key.
     *
     * @param key startTimeMilli to match
     */
    @Query("SELECT * from my_inventory_table WHERE itemId = :key")
    fun get(key: Long): InventoryItem?

    /**
     * Deletes all values from the table.
     *
     * This does not delete the table, only its contents.
     */
    @Query("DELETE FROM my_inventory_table")
    fun clear()

    @Query("DELETE FROM my_inventory_table WHERE itemId =:itemId")
    fun delete(itemId: Long)

    //    @Transaction
    @Query("SELECT * FROM my_inventory_table")
    fun getItemsWithBag(): LiveData<List<ItemWithBag>>

    @Entity
    data class ItemWithBag(
        @Embedded val item: InventoryItem,
        @Relation(
            parentColumn = "bagOwnerId",
            entityColumn = "bagId"
        )
        val bag: BagItem
    )
}

...