如何在Mockito-Kotlin中模拟Lambda类型方法参数?
问题背景
定义了如下接口:
interface DistanceChecker { fun checkDistance(locationData: LocationData, result: (Boolean) -> Unit) }
该方法通过依赖注入进入业务逻辑,无需显式调用。尝试用以下代码模拟该方法:
doAnswer { it.getArgument<(Boolean) -> Unit>(1).invoke(true) null }.`when`(distanceChecker).checkDistance( same( LocationData( LatLng(.0, .0), LatLng(.0, .0), .0 ) ), any() )
运行时触发存根错误:
- this invocation of 'checkDistance' method:
distanceChecker.checkDistance(
LocationData(point=0.0_0.0, location=0.0_0.0, zoneRadius=0.0),
(kotlin.Boolean) -> kotlin.Unit
);- has following stubbing(s) with different arguments:
- distanceChecker.checkDistance(
LocationData(point=0.0_0.0, location=0.0_0.0, zoneRadius=0.0),
null
);
解决方法
问题根源是Mockito默认any()匹配器对Kotlin非空Lambda参数的兼容性问题:Kotlin Lambda是非空类型,但原生Mockito的any()会被解析为null,导致存根参数与实际调用参数不匹配。可以通过以下两种方式修复:
方式1:使用Mockito-Kotlin适配库
若项目已引入mockito-kotlin依赖,直接使用其适配后的any(),它能正确识别Kotlin非空类型:
import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.doAnswer doAnswer { it.getArgument<(Boolean) -> Unit>(1).invoke(true) }.`when`(distanceChecker).checkDistance( same(LocationData(LatLng(.0, .0), LatLng(.0, .0), .0)), any() )
方式2:手动指定非空匹配器
不想引入额外库的话,给原生Mockito的any()明确指定Lambda类型,或者用argThat匹配任意非空Lambda:
// 明确指定Lambda类型 doAnswer { it.getArgument<(Boolean) -> Unit>(1).invoke(true) null }.`when`(distanceChecker).checkDistance( same(LocationData(LatLng(.0, .0), LatLng(.0, .0), .0)), any<(Boolean) -> Unit>() )
或用argThat:
// 匹配任意非空Lambda doAnswer { it.getArgument<(Boolean) -> Unit>(1).invoke(true) null }.`when`(distanceChecker).checkDistance( same(LocationData(LatLng(.0, .0), LatLng(.0, .0), .0)), argThat { true } )
额外注意点
如果业务中创建的LocationData是新实例而非存根时的同一个对象,same()(引用相等匹配)会失效,此时应该改用eq()(值相等匹配),前提是LocationData已正确实现equals()方法:
eq(LocationData(LatLng(.0, .0), LatLng(.0, .0), .0))
内容的提问来源于stack exchange,提问作者apleuxa12
相关产品推荐
相关产品推荐

