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

Mockk如何通过returnsArgument返回Result包装对象?

Mockk returnsArgument 为啥能让 Result<T> 直接返回 T?

关键:Kotlin Result<T> 是内联值类

Kotlin里的Result<T>是内联值类(inline value class),它的底层实现是直接把包装的T实例作为自身运行时的载体——简单说,运行时Result<Entity>其实就是Entity对象本身,只是编译期帮我们做了类型校验,不让随便乱转。

Mockk的returnsArgument之所以能这么玩,是因为:

  • 它内部用了非受检类型转换(加了@Suppress("UNCHECKED_CAST")跳过编译检查)
  • 运行时Result<T>和T是同一个东西,所以强转不会报错——这完全是内联值类的特性给的便利。

为啥自己手动转就报错?

你自己写val result: Result<Entity> = entity as Result<Entity>会报错,是因为Kotlin编译期会严格卡内联值类的类型转换规则,不允许直接把T转成Result<T>。但Mockk是靠动态代理和反射生成Mock对象的,绕开了编译期的检查,直接在运行时做了转换,刚好碰上个运行时类型完全一致的情况,就成了。

不是所有包装类都能用这招

这特性只适用于内联值类,比如你自己定义的:

@JvmInline
value class UserWrapper(val user: User)

用Mockk的returnsArgument返回User去冒充UserWrapper也能跑通。但如果是普通的包装类,比如data class UserWrapper(val user: User),运行时是独立的对象,这么玩直接就会抛ClassCastException——因为User和UserWrapper根本不是一个类型。

试一下就懂

自定义内联值类的测试代码:

@JvmInline
value class EntityWrapper(val value: Entity)

interface Service {
    fun wrap(entity: Entity): EntityWrapper
}

// Mock测试
val mockedService = mockk<Service>()
every { mockedService.wrap(any()) } returnsArgument 0
val wrapper = mockedService.wrap(Entity())
println(wrapper.value) // 正常输出,没异常

换成普通data class的话,跑这段代码直接就会炸。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 23:33:22