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
相关产品推荐
相关产品推荐

