Mockito Mock无法返回分页/流数据问题排查
问题描述
我在Mock仓库返回的分页数据时遇到问题,需要测试ViewModel中的如下逻辑:
// watch for filter to change, on charge reset the paging query val items = filterParameter.switchMap { filter -> Pager( config = PagingConfig(pageSize = 20), initialKey = null, pagingSourceFactory = { repository.observeItems(filter) } ).liveData }.asFlow().map { pagingData -> pagingData .map { ListItem(it) } .insertSeparators { item1: ListItem?, item2: ListItem? -> // 要测试的分隔符逻辑 } }.cachedIn(viewModelScope)
测试代码如下:
@Test fun testTransformation() = runTest { val repository = mock<MyRepository>() `when`(repository.observeItems(Mockito.any())) .thenAnswer { val flow = flowOf( listOf( Item( id = "1", date = Date() ) ) ) val pagingSourceFactory = flow.asPagingSourceFactory(coroutineScope = this) pagingSourceFactory() } val viewModel = MyViewModel( repository = repository, ) val items: Flow<PagingData<ListItem>> = viewModel.items val snapshot: List<ListItem> = items.asSnapshot() {} Assert.assertEquals(1, snapshot.size) // 失败,快照大小为0而非预期的1 }
已确认测试时ViewModel中的Pager已初始化,且Mock Flow已被调用,但无法获取Mock数据,断言快照大小为0,求解决思路。
解决思路
触发filterParameter发射值:ViewModel中
items是通过filterParameter.switchMap创建的,如果filterParameter没有发射任何值,整个流不会启动。测试时需要给filterParameter设置一个有效过滤值,示例:// 假设filterParameter是MutableStateFlow<Filter>类型 viewModel.filterParameter.value = Filter()修正Mock的PagingSource创建方式:
flow.asPagingSourceFactory依赖的协程作用域可能与测试环境不兼容,建议直接返回一个预定义数据的PagingSource实现,示例:`when`(repository.observeItems(Mockito.any())) .thenReturn(object : PagingSource<Int, Item>() { override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Item> { return LoadResult.Page( data = listOf(Item(id = "1", date = Date())), prevKey = null, nextKey = null ) } override fun getRefreshKey(state: PagingState<Int, Item>): Int? = null })正确收集分页数据:
asSnapshot可能无法正确等待分页数据加载完成,建议改用collectLatest配合列表收集数据,并调用advanceUntilIdle()确保协程执行完毕,示例:val collectedItems = mutableListOf<ListItem>() val job = launch { items.collectLatest { pagingData -> pagingData.collect { item -> collectedItems.add(item) } } } advanceUntilIdle() job.cancel() Assert.assertEquals(1, collectedItems.size)处理cachedIn的作用域问题:
cachedIn(viewModelScope)会将数据缓存到ViewModel的作用域中,测试时需确保viewModelScope使用测试兼容的调度器,可在创建ViewModel时传入测试用的CoroutineScope。
内容的提问来源于stack exchange,提问作者lostintranslation
相关产品推荐
相关产品推荐

