本文介绍了使用远程中介和分页源对分页 3 的存储库进行单元测试的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我正在尝试对 android 中的存储库类进行单元测试,该类使用带有远程中介和分页源的分页.
I am trying to unit test a repository class in android which is using paging with a remote mediator and paging source.
但是当我运行测试时返回的结果是空的,虽然实际应该包含测试项.
But when I run the test the returned result is empty, although actual should contain the test item.
如下:
这是我的仓库
class PostsRepository @Inject constructor(
private val postsApi: AutomatticPostsApi,
private val postsDao: PostDao
) : IPostsRepository {
@ExperimentalPagingApi
override fun loadPosts(): Flow<PagingData<Post>> {
println("loadPosts")
return Pager(
config = PagingConfig(20),
initialKey = 1,
remoteMediator = PostsPageRemoteMediator(
postsApi,
postsDao
),
pagingSourceFactory = { postsDao.getPostsPagingSource() }
).flow.map { pagingData ->
pagingData.map { it.toPost() }
}
}
}
这是我的 UT
@ExperimentalCoroutinesApi
@ExperimentalPagingApi
class PostsRepositoryTest {
@get:Rule
val instantTaskExecutorRule = InstantTaskExecutorRule()
private val coroutineDispatcher = TestCoroutineDispatcher()
private lateinit var postDao: FakePostDao
private lateinit var postsApi: CommonAutomatticPostsApi
private val remotePosts = listOf(createDummyPostResponse())
private val domainPosts = remotePosts.map { it.toPost() }
//GIVEN: subject under test
private lateinit var postsRepository: PostsRepository
@Before
fun createRepository() = coroutineDispatcher.runBlockingTest {
postsApi = CommonAutomatticPostsApi(remotePosts.toMutableList())
postDao = FakePostDao()
postsRepository = PostsRepository(postsApi, postDao)
}
@Test
fun loadPosts_returnsCorrectPosts() = runBlockingTest {
//WHEN: posts are retrieved from paging source
launch {
postsRepository.loadPosts().collect { pagingData ->
val posts = mutableListOf<Post>()
pagingData.map {
posts.add(it)
println(it)
}
//THEN: retrieved posts should be the remotePosts
assertThat(posts, IsEqual(domainPosts))
}
}
}
}
这里是 FakeApi、FakePagingSource 和 FakeDao
class CommonAutomatticPostsApi(val posts: MutableList<PostResponse> = mutableListOf()) : AutomatticPostsApi {
companion object {
const val SUBSCRIBER_COUNT = 2L
const val AUTHOR_NAME = "RR"
}
override suspend fun loadPosts(page: Int, itemCount: Int): PostsResponse {
println("Loaded")
return PostsResponse(posts.size.toLong(), posts)
}
}
class FakePostsPagingSource() : PagingSource<Int, PostEntity>() {
var triggerError = false
var posts: List<PostEntity> = emptyList()
set(value) {
println("set")
field = value
invalidate()
}
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, PostEntity> {
println("load")
if (triggerError) {
return LoadResult.Error(Exception("A test error triggered"))
}
println("not error")
return LoadResult.Page(
data = posts,
prevKey = null,
nextKey = null
)
}
override fun getRefreshKey(state: PagingState<Int, PostEntity>): Int? {
println("refresh")
return state.anchorPosition ?: 1
}
}
class FakePostDao(val posts: MutableList<PostEntity> = mutableListOf()) : PostDao {
val pagingSource = FakePostsPagingSource()
override suspend fun insertPosts(posts: List<PostEntity>) {
this.posts.addAll(posts)
println("insertPosts")
updatePagingSource()
}
override suspend fun updatePost(post: PostEntity) {
onValidPost(post.id) {
posts[it] = post
updatePagingSource()
}
}
private fun onValidPost(postId: Long, block: (index: Int) -> Unit): Boolean {
println("onValidPost")
val index = posts.indexOfFirst { it.id == postId }
if (index != -1) {
block(index)
return true
}
return false
}
override suspend fun updatePost(postId: Long, subscriberCount: Long) {
onValidPost(postId) {
posts[it] = posts[it].copy(subscriberCount = subscriberCount)
updatePagingSource()
}
}
override suspend fun getPostById(postId: Long): PostEntity? {
val index = posts.indexOfFirst { it.id == postId }
return if (index != -1) {
posts[index]
} else {
null
}
}
override suspend fun getPosts(): List<PostEntity> {
println("getPosts")
return posts
}
override fun getPostsPagingSource(): PagingSource<Int, PostEntity> {
println("getPostsPagingSource")
return pagingSource
}
override suspend fun clearAll() {
posts.clear()
updatePagingSource()
}
private fun updatePagingSource() {
println("updatePagingSource")
pagingSource.posts = posts
}
@Transaction
override suspend fun refreshPosts(newPosts: List<PostEntity>) {
println("refreshPosts")
clearAll()
insertPosts(newPosts)
}
}
推荐答案
PagingData 测试 (kotlin),版本:3.0.0-rc01.感谢法里德.
PagingData test (kotlin), version: 3.0.0-rc01. Thanks to Farid.
private suspend fun <T : Any> PagingData<T>.collectDataForTest(): List<T> {
val dcb = object : DifferCallback {
override fun onChanged(position: Int, count: Int) {}
override fun onInserted(position: Int, count: Int) {}
override fun onRemoved(position: Int, count: Int) {}
}
val items = mutableListOf<T>()
val dif = object : PagingDataDiffer<T>(dcb, TestCoroutineDispatcher()) {
override suspend fun presentNewList(
previousList: NullPaddedList<T>,
newList: NullPaddedList<T>,
newCombinedLoadStates: CombinedLoadStates,
lastAccessedIndex: Int,
onListPresentable: () -> Unit
): Int? {
for (idx in 0 until newList.size)
items.add(newList.getFromStorage(idx))
onListPresentable()
return null
}
}
dif.collectFrom(this)
return items
}
用法:
// searchHistoryList: Flow<PagingData<Your Data type>>
val tmp = useCase.searchHistoryList.take(1).toList().first()
// result: List<Your Data type>
val result = tmp.collectDataForTest()
assertEquals(expect, result)
这篇关于使用远程中介和分页源对分页 3 的存储库进行单元测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!