4

我的问题实际上很笼统。我想知道如何对从Paging 3返回PagingSource的Room Dao查询进行单元测试。

我有一个Room Dao查询:

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

我想知道如何对这个查询进行单元测试。

到目前为止我尝试过的(使用内存中的Room数据库进行测试):

@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])
}

然而,这并没有通过:

junit.framework.AssertionFailedError:预期:androidx.paging.PagingData@7d6c23a1 实际:androidx.paging.PagingData@321123d2

不知道如何正确处理。任何帮助将不胜感激!

4

3 回答 3

6

PagingData是内部事件流的包装器,您无法直接比较它,并且您得到的错误是按预期抛出引用不等式。

相反,您应该PagingSource直接查询以比较其中的数据, LoadResult.Page或者您需要将其连接到演示者 API,例如AsyncPagingDataDifferorPagingDataAdapter并使用.snapshot()

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

如果你需要一个测试范围,我推荐runBlockingTest来自 kotlinx.coroutines.test 库

PagingSource直接查询,它有一个暂停.load()方法,因此您可以简单地将其包装runBlockingTest并断言结果:

@Test
fun test() = runBlockingTest {
  val pagingSource = MyPagingSource()
  val actual = pagingSource.load(LoadParams.Refresh(...))
  assertEquals(actual as? LoadResult.Page)?.data, listOf(...))
}
于 2021-01-11T18:30:05.160 回答
0

以防万一您需要模拟 PagingSource:

创建辅助类 PagingSourceUtils.kt 示例:

class PagingSourceUtils<T : Any>(
    private val data: List<T>
) : PagingSource<Int, T>() {
    override fun getRefreshKey(state: PagingState<Int, T>): Int? {
        return 0
    }

    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, T> {
        return LoadResult.Page(
            data = data,
            prevKey = null,
            nextKey = null
        )
    }
}

你的测试.kt

@Test
    fun `should success get Chocolate `() {

         val chocolates = listOf(Chocolate(
             name = "Dove"
         )) 

        runBlocking {
            val tData = PagingSourceUtils(chocolates)
            `when`(dao.getChocolateListData()).thenReturn(tData)

            val data = ...

            val actual = ..

            assertEquals(actual, data)
        }
    }
于 2021-06-15T10:08:45.767 回答
0

根据标记为正确的答案,我自己做了,不是很漂亮,但如果有任何反馈我会很高兴,至少可以完成工作,在此先感谢。

fun <PaginationKey: Any, Model: Any>PagingSource<PaginationKey, Model>.getData(): List<Model> {
    val data = mutableListOf<Model>()
    val latch = CountDownLatch(1)
    val job = CoroutineScope(Dispatchers.Main).launch {
        val loadResult: PagingSource.LoadResult<PaginationKey, Model> = this@getData.load(
            PagingSource.LoadParams.Refresh(
                key = null, loadSize = Int.MAX_VALUE, placeholdersEnabled = false
            )
        )
        when (loadResult) {
            is PagingSource.LoadResult.Error -> throw loadResult.throwable
            is PagingSource.LoadResult.Page -> data.addAll(loadResult.data)
        }
        latch.countDown()
    }
    latch.await()
    job.cancel()
    return data
}

所以在你的测试中,你可以像这样使用它

val obtainedData = myDao.getSomePagingSource().getData()

assertEquals(expectedData, obtainedData)

警告:你会看到一个相当长的日志

WARNING: pageSize on the LegacyPagingSource is not set.
When using legacy DataSource / DataSourceFactory with Paging3, page size...
于 2021-07-09T17:06:56.003 回答