androidtestingandroid-room

Query SQLite Database in Android test with Room


I am writing an app that has a form where the user enters data:

    Column {
        TextField(
            label = { Text(text = stringResource(id = R.string.brand)) },
            value = state.value.brand,
            onValueChange = { state.value = state.value.copy(brand = it) }
        )
        // ... and more
    }

When the user taps the save button, I use Room API to save the data to a local SQLite database:

fun saveCard(db: BaseballCardDatabase, cardState: BaseballCardState) {
    val newCard = cardState.toBaseballCard()
    runBlocking {
        launch {
            db.baseballCardDao.insertBaseballCard(newCard)
        }
    }
}

Now I want to write a test for this form. I can successfully automate entering data into the form and clicking the save button:

        composeTestRule
            .onNodeWithText("Brand")
            .assertIsDisplayed()
            .performTextInput(card.brand)
        // ... etc
        composeTestRule
            .onNodeWithContentDescription("Save")
            .performClick()

Now I want to verify that a new row was inserted in the database. How do I query the database from a test?

My attempt was like this:

        val context = InstrumentationRegistry.getInstrumentation().targetContext
        val db = inMemoryDatabaseBuilder(context, BaseballCardDatabase::class.java).build()

        runBlocking {
            launch {
                val savedCard = db.baseballCardDao.getBaseballCards().single()
                assert(savedCard == card)
            }
        }

But this just hangs forever. I assume it is because of the runBlocking context, but not entirely sure. How do I do this correctly?


Solution

  • try it:

    CoroutineScope(Dispatchers.IO).launch {
            val savedCard = db.baseballCardDao.getBaseballCards().single()
            assert(savedCard == card)
        }
    

    when you use runBlocking. it will block the main thread. if you use runblocking. it should crash the app not hangs. Also this is just a way for you to test. In fact you should create a coroutine object to be able to use it like this.

        val coroutineScope = CoroutineScope(Dispatchers.IO)
        coroutineScope.launch {
            val savedCard = db.baseballCardDao.getBaseballCards().single()
            assert(savedCard == card)
        }
    

    or use the viewModelScope object in ViewModel(if you use ViewModel)