You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 19:36:04