如何对 Returns 来自 Paging 3 的 PagingSource 的 Room Dao 查询进行单元测试
How to Unit Test a Room Dao Query that Returns a PagingSource From Paging 3
我的问题其实很笼统。我想知道如何对 Room Dao 查询 returns a PagingSource 进行单元测试来自 第 3 页.
我有一个 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: Expected
:androidx.paging.PagingData@7d6c23a1 Actual
:androidx.paging.PagingData@321123d2
不确定如何正确处理。任何帮助将不胜感激!
PagingData
是内部事件流的包装器,您不能直接比较它,并且您得到的错误是按预期抛出引用不平等。
相反,您应该直接查询 PagingSource
以比较 LoadResult.Page
中的数据,或者您需要将其连接到演示者 API,例如 AsyncPagingDataDiffer
或 PagingDataAdapter
并使用 .snapshot()
val flow = Pager(..).flow
val adapter = MyPagingDataAdapter()
val job = launch {
flow.collectLatest { adapter.submitData(it) }
}
// Do your asserts here
job.cancel()
如果您需要测试范围,我推荐 kotlinx.coroutines.test 库中的 runBlockingTest
要直接查询PagingSource
,它有一个挂起的.load()
方法,所以你可以简单地将它包装在runBlockingTest
中并断言结果:
@Test
fun test() = runBlockingTest {
val pagingSource = MyPagingSource()
val actual = pagingSource.load(LoadParams.Refresh(...))
assertEquals(actual as? LoadResult.Page)?.data, listOf(...))
}
以防万一你需要模拟 PagingSource:
创建助手 class 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
)
}
}
YourTest.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)
}
}
根据标记为正确的答案,我自己做了一个,虽然不是很好,但至少完成了工作,如果有任何反馈我会很高兴,提前致谢。
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...
我的问题其实很笼统。我想知道如何对 Room Dao 查询 returns a PagingSource 进行单元测试来自 第 3 页.
我有一个 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: Expected :androidx.paging.PagingData@7d6c23a1 Actual :androidx.paging.PagingData@321123d2
不确定如何正确处理。任何帮助将不胜感激!
PagingData
是内部事件流的包装器,您不能直接比较它,并且您得到的错误是按预期抛出引用不平等。
相反,您应该直接查询 PagingSource
以比较 LoadResult.Page
中的数据,或者您需要将其连接到演示者 API,例如 AsyncPagingDataDiffer
或 PagingDataAdapter
并使用 .snapshot()
val flow = Pager(..).flow
val adapter = MyPagingDataAdapter()
val job = launch {
flow.collectLatest { adapter.submitData(it) }
}
// Do your asserts here
job.cancel()
如果您需要测试范围,我推荐 kotlinx.coroutines.test 库中的 runBlockingTest
要直接查询PagingSource
,它有一个挂起的.load()
方法,所以你可以简单地将它包装在runBlockingTest
中并断言结果:
@Test
fun test() = runBlockingTest {
val pagingSource = MyPagingSource()
val actual = pagingSource.load(LoadParams.Refresh(...))
assertEquals(actual as? LoadResult.Page)?.data, listOf(...))
}
以防万一你需要模拟 PagingSource:
创建助手 class 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
)
}
}
YourTest.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)
}
}
根据标记为正确的答案,我自己做了一个,虽然不是很好,但至少完成了工作,如果有任何反馈我会很高兴,提前致谢。
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...