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

如何组合带不同上下文接收器的mockk与withClient函数?

问题场景

我用Kotlin的上下文接收器(context receivers)做「本地化依赖注入」传递客户端上下文,生产代码跑起来没问题,但测试用mockk模拟时卡壳了——因为被mock的方法需要ClientProvider上下文,直接写mock代码会编译失败。

先贴下生产代码的核心实现:

// 用withClient传递ClientProvider上下文
fun <T> withClient(client: Client, block: ClientProvider.() -> T) =
    ClientProvider { client }.block()

// 业务类,方法依赖ClientProvider上下文
class MyService {
  context(ClientProvider)
  fun methodUsingClient() {}
}

测试时直接mock会报错,因为methodUsingClient()必须在ClientProvider上下文里调用:

val myService: MyService = mockk { every { methodUsingClient() } just runs } // 编译失败,提示缺少ClientProvider上下文

我试着写了个mockkWithClient函数想把mockk和withClient结合,但函数本身编译不过:

inline fun <reified T : Any> mockkWithClient(noinline block: context(T) ClientProvider.() -> Unit) =
    mockk<T> { withClient(mockk(), block) }

编译器报类型不匹配:

Type mismatch.
Required:
ClientProvider.() → TypeVariable(T)
Found:
context(T) ClientProvider.() → Unit
解决方法

核心问题是mockk的lambda参数是T.() -> Unit(以被mock的T实例为接收者),而我们需要把这个接收者和ClientProvider上下文结合起来。调整mockkWithClient的block参数类型,让它同时持有T和ClientProvider两个上下文即可。

正确的实现代码:

inline fun <reified T : Any> mockkWithClient(noinline block: context(T, ClientProvider) () -> Unit) =
    mockk<T> {
        // 创建mock的Client,用withClient注入上下文
        withClient(mockk()) {
            // 这里已经有ClientProvider上下文,同时把当前的mock实例(this@mockk)作为T上下文传入
            block()
        }
    }

调用方式和你预想的完全一致,编译运行都正常:

val myService: MyService = mockkWithClient { 
    every { methodUsingClient() } just runs 
}
为啥原来的写法不行?
  • 你原来定义的block是context(T) ClientProvider.() -> Unit,意思是:这个函数的接收者是ClientProvider,同时还需要T作为额外上下文。但withClient期望的参数是ClientProvider.() -> T,类型完全对不上,所以编译器报错。
  • 正确的block类型应该是context(T, ClientProvider) () -> Unit,表示这个函数需要同时拥有T(被mock的实例)和ClientProvider两个上下文。在withClient的lambda内部,我们已经有了ClientProvider上下文,再加上mockk lambda里的T实例(this@mockk),刚好满足block的上下文要求,自然就能正常调用了。

内容的提问来源于stack exchange,提问作者David Kubecka

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 23:45:38