如何使用Kotest和Mockk为返回LiveData的方法编写单元测试并修复报错
问题原因及解决方案
错误原因
测试代码存在两个核心问题,直接导致报错且无实际验证意义:
- 错误断言:
verify { ... }是Mockk提供的方法调用验证函数,它的返回值为Unit,你将verify的返回值和预期的LiveData对象做匹配,自然会抛出expected:MutableLiveData but was:Unit的错误。 - 测试对象错误:你直接Mock了要测试的
FolderRepository类本身,所有方法的返回值都是你伪造的stub结果,就算测试通过也完全无法验证真实FolderRepository的逻辑正确性。
正确实现逻辑
FolderRepository的核心依赖是Room的DAO层,所以正确的测试逻辑应该是:
- Mock DAO层对象,stub DAO的查询方法返回你构造的测试用
LiveData<Folder?>对象 - 实例化真实的
FolderRepository对象,将Mock的DAO作为构造参数传入 - 调用
repository.getFolder(id)拿到返回结果,和预期的LiveData做断言匹配 - 最后用
verify验证DAO的对应查询方法被正确调用即可
完整可运行测试代码
注意:如果需要验证LiveData内部存储的数值,需要导入
androidx.arch.core:core-testing依赖,添加InstantTaskExecutorRule让LiveData的任务同步执行,避免异步问题。
import androidx.arch.core.executor.testing.InstantTaskExecutorRule import androidx.lifecycle.MutableLiveData import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe import io.mockk.every import io.mockk.mockk import io.mockk.verify import my.package.Folder import my.package.FolderDao import my.package.FolderRepository import org.junit.Rule class FolderRepositoryTest: FunSpec({ // 让LiveData的更新同步执行,可选,如果你需要校验LiveData内部的值就必须加 @get:Rule val instantTaskExecutorRule = InstantTaskExecutorRule() // Mock依赖的DAO层,而不是Repository本身 val folderDao = mockk<FolderDao>() // 实例化真实的待测试Repository对象 val repository = FolderRepository(folderDao) val testFolder = Folder( // 填充测试用的Folder字段 ) val expectedLiveData = MutableLiveData<Folder?>(testFolder) test("FolderRepository getFolder works as expected") { val testId = testFolder.id.toLong() // stub DAO的查询方法返回预期的LiveData every { folderDao.selectFolderById(testId) } returns expectedLiveData // 调用真实Repository的方法 val resultLiveData = repository.getFolder(testId) // 断言返回结果符合预期 resultLiveData shouldBe expectedLiveData // 可选:校验LiveData内部存储的值 resultLiveData.value shouldBe testFolder // 验证DAO的方法被正确调用 verify(exactly = 1) { folderDao.selectFolderById(testId) } } })
内容的提问来源于stack exchange,提问作者Jun Du
相关产品推荐
相关产品推荐

