如何使用Kotlin的Mockk框架测试含async操作的协程异步挂起函数
使用Mockk测试Kotlin协程函数fetchTwoDocs的方案
前置依赖
首先确保你的测试配置里已经引入了必要的依赖(Gradle配置示例):
testImplementation "io.mockk:mockk:1.13.8" testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3" testImplementation "junit:junit:4.13.2"
测试实现
假设业务代码结构
首先我们默认fetchDoc和fetchTwoDocs属于同一个仓库类,结构如下:
class DocRepository { suspend fun fetchDoc(id: Int): String { // 实际为网络请求/数据库查询逻辑 return "doc$id" } suspend fun fetchTwoDocs() = coroutineScope { val deferredOne = async { fetchDoc(1) } val deferredTwo = async { fetchDoc(2) } deferredOne.await() deferredTwo.await() } }
测试代码编写
我们的测试目标是验证fetchTwoDocs确实调用了两次fetchDoc,入参分别为1和2,且返回结果符合预期:
import io.mockk.coEvery import io.mockk.coVerify import io.mockk.spyk import kotlinx.coroutines.test.runTest import org.junit.Assert.assertEquals import org.junit.Test class DocRepositoryTest { // 用spy生成类实例,保留真实的fetchTwoDocs逻辑,仅mock fetchDoc private val testRepository = spyk(DocRepository()) @Test fun `fetchTwoDocs 应正确调用两次fetchDoc并返回结果`() = runTest { // mock挂起函数fetchDoc的返回值 coEvery { testRepository.fetchDoc(1) } returns "文档1内容" coEvery { testRepository.fetchDoc(2) } returns "文档2内容" // 执行待测试方法 val result = testRepository.fetchTwoDocs() // 验证调用行为符合预期 coVerify(exactly = 1) { testRepository.fetchDoc(1) } coVerify(exactly = 1) { testRepository.fetchDoc(2) } // 按你给出的fetchTwoDocs实现,返回值是第二个await的结果,所以做如下校验 assertEquals("文档2内容", result) // 如果你实际修改fetchTwoDocs返回两个结果,比如返回Pair(deferredOne.await(), deferredTwo.await()),则按实际校验即可 } }
特殊场景适配
- 如果
fetchDoc是其他依赖类的方法,直接mock对应依赖类即可,不需要用spy:// 假设DocRepository依赖DocDataSource,fetchDoc属于DocDataSource private val mockDataSource = mockk<DocDataSource>() private val testRepository = DocRepository(mockDataSource) - 如果
fetchDoc是顶层函数,需要用mockkStatic做静态mock:// 传入顶层函数所在文件生成的Kt类全路径 mockkStatic("com.xxx.xxx.UtilsKt") coEvery { fetchDoc(1) } returns "文档1内容" // 测试结束后销毁静态mock unmockkStatic("com.xxx.xxx.UtilsKt")
注意事项
- 测试挂起函数时必须用Mockk提供的
coEvery、coVerify等带co前缀的API,普通every/verify仅支持非挂起函数 - 协程测试需要用
kotlinx-coroutines-test提供的runTest启动测试协程,自动处理调度器生命周期 - 如果需要验证两个
async是并行执行的,可以给fetchDoc(1)加100ms延迟、fetchDoc(2)不加,验证整个方法执行耗时接近100ms而非200ms即可,普通业务测试不需要做这个校验。
内容的提问来源于stack exchange,提问作者Compose Learner
相关产品推荐
相关产品推荐

