androidandroid-roomkotlin-flowandroid-paging-3android-unit-testing

How to Unit Test a Room Dao Query that Returns a PagingSource From Paging 3


My question is actually quite generic. I want to know how to unit test a Room Dao query that returns a PagingSource From Paging 3.

I have a Room Dao query:

    @Query("SELECT * FROM database")
    fun getChocolateListData(): PagingSource<Int, Chocolate>

I'm wondering how this query can be unit tested.

What I've tried so far (using in-memory Room database for testing):

@FlowPreview
@Test
fun saveChocolateToDbSavesData() = runBlocking {
    val dao: Dao by inject()

    val chocolate = Chocolate(
        name = "Dove"
    )
    dao.saveChocolate(chocolate) 

    val pagingSourceFactory = { dao.getChocolateListData() }
    val pagingDataFlow: Flow<PagingData<Chocolate>> = Pager(
        config = PagingConfig(
            pageSize = 50,
            maxSize = 200,
            enablePlaceholders = false
        ),
        pagingSourceFactory = pagingSourceFactory
    ).flow

    val chocolateListFlow = pagingDataFlow.testIn(coroutinesTestRule)
    Assert.assertEquals(PagingData.from(listOf(chocolate)), chocolateListFlow.emissions[0])
}

This doesn't pass, however:

junit.framework.AssertionFailedError: Expected :androidx.paging.PagingData@7d6c23a1 Actual :androidx.paging.PagingData@321123d2

Not sure how to get it right. Any help would be greatly appreciated!


Solution

  • PagingData is wrapper around an internal event stream, you cannot compare it directly and the error you are getting is throwing referential inequality as expected.

    Instead you should either query the PagingSource directly to compare the data in LoadResult.Page or you'll need to hook it up to a presenter API such as AsyncPagingDataDiffer or PagingDataAdapter and use .snapshot()

    val flow = Pager(..).flow
    val adapter = MyPagingDataAdapter()
    val job = launch {
        flow.collectLatest { adapter.submitData(it) }
    }
    // Do your asserts here
    job.cancel()
    

    if you need a test scope, I recommend runBlockingTest from the kotlinx.coroutines.test library

    To query PagingSource directly, it has a single suspending .load() method, so you can simply wrap it in runBlockingTest and assert the result:

    @Test
    fun test() = runBlockingTest {
      val pagingSource = MyPagingSource()
      val actual = pagingSource.load(LoadParams.Refresh(...))
      assertEquals(actual as? LoadResult.Page)?.data, listOf(...))
    }