如何从分页3测试分页数据 [英] How To Test PagingData From Paging 3

查看:134
本文介绍了如何从分页3测试分页数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的 ViewModel 有一个返回 PagingData 流的方法.在我的应用程序中,数据是从远程服务器上获取的,然后保存到 Room (房间的唯一来源):

My ViewModel has a method which returns a flow of PagingData. In my app, the data is fetched from the remote server, which is then saved to Room (the single source of truth):

fun getChocolates(): Flow<PagingData<Chocolate>> {
    val pagingSourceFactory = { dao().getChocolateListData() }
    return Pager(
        config = PagingConfig(
            pageSize = NETWORK_PAGE_SIZE,
            maxSize = MAX_MEMORY_SIZE,
            enablePlaceholders = false
        ),
        remoteMediator = ChocolateRemoteMediator(
                api,
                dao
        ),
        pagingSourceFactory = pagingSourceFactory
    ).flow
}

如何测试此方法?我想测试返回的流是否包含正确的数据.

How do I test this method? I want to test if the returning flow contains the correct data.

到目前为止我已经尝试过的:

What I've tried so far:

@InternalCoroutinesApi
@Test
fun getChocolateListReturnsCorrectData() = runBlockingTest {
    val chocolateListDao: ChocolateListDao by inject()
    val chocolatesRepository: ChocolatesRepository by inject()
    val chocolateListAdapter: ChocolateListAdapter by inject()

    // 1
    val chocolate1 = Chocolate(
        name = "Dove"
    )
    val chocolate2 = Chocolate(
        name = "Hershey's"
    )

    // 2
    // You need to launch here because submitData suspends forever while PagingData is alive
    val job = launch {
        chocolatesRepository.getChocolateListStream().collectLatest {
            chocolateListAdapter.submitData(it)
        }
    }

    // Do some stuff to trigger loads
    chocolateListDao.saveChocolate(chocolate1, chocolate2)

    // How to read from adapter state, there is also .peek() and .itemCount
    assertEquals(listOf(chocolate1, chocolate2).toMutableList(), chocolateListAdapter.snapshot())

    // We need to cancel the launched job as coroutines.test framework checks for leaky jobs
    job.cancel()
}

我想知道自己是否走对了.任何帮助将不胜感激!

I'm wondering if I'm on the right track. Any help would be greatly appreciated!

推荐答案

我发现使用 cashapp中的涡轮会容易得多.( JakeWharton 再次救出:P)

I found using Turbine from cashapp would be much much easier.(JakeWharton comes to rescue again :P)

testImplementation "app.cash.turbine:turbine:0.2.1"

根据您的代码,我认为您的测试用例应如下所示:

According to your code I think your test case should looks like:

@ExperimentalTime
@ExperimentalCoroutinesApi
@Test
fun `test if receive paged chocolate data`() = runBlockingTest {

    val expected = listOf(
      Chocolate(name = "Dove"),
      Chocolate(name = "Hershey's")
    )

    coEvery {
        dao().getChocolateListData()
    }.returns(
        listOf(
            Chocolate(name = "Dove"),
            Chocolate(name = "Hershey's")
        )
    )

    launchTest {
        viewModel.getChocolates().test(
            timeout = Duration.ZERO,
            validate = {
                val collectedData = expectItem().collectData()
                assertEquals(expected, collectedData)
                expectComplete()
            })
    }
}

我还准备了一个基本的ViewModelTest类,用于处理许多设置和tearDown任务:

I also prepare a base ViewModelTest class for taking care of much of setup and tearDown tasks:

abstract class BaseViewModelTest {
    @get:Rule
    open val instantTaskExecutorRule = InstantTaskExecutorRule()

    @get:Rule
    open val testCoroutineRule = CoroutineTestRule()

    @MockK
    protected lateinit var owner: LifecycleOwner

    private lateinit var lifecycle: LifecycleRegistry

    @Before
    open fun setup() {
        MockKAnnotations.init(this)

        lifecycle = LifecycleRegistry(owner)
        every { owner.lifecycle } returns lifecycle
    }

    @After
    fun tearDown() {
        clearAllMocks()
    }

    protected fun initCoroutine(vm: BaseViewModel) {
        vm.apply {
            setViewModelScope(testCoroutineRule.testCoroutineScope)
            setCoroutineContext(testCoroutineRule.testCoroutineDispatcher)
        }
    }

    @ExperimentalCoroutinesApi
    protected fun runBlockingTest(block: suspend TestCoroutineScope.() -> Unit) =
        testCoroutineRule.runBlockingTest(block)


    protected fun launchTest(block: suspend TestCoroutineScope.() -> Unit) =
        testCoroutineRule.testCoroutineScope.launch(testCoroutineRule.testCoroutineDispatcher) { block }

}

关于扩展功能 collectData(),该功能是从另一篇帖子的答案中借来的(谢谢 @Farid !!)

As for extension function collectData() that's borrowed from answer from another post (Thanks @Farid!!)

和介绍涡轮的幻灯片放映>

And a slide show introducing turbine

这篇关于如何从分页3测试分页数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆