2017-10-11 64 views
0

我的工作中,我试图嘲弄的输入,功能的科特林罐子嘲笑的Mockito表现得像个间谍:科特林

class MyService 
fun serviceFunction(input: ClassFromAnotherLibrary): Output { 
    val foo = input.memberFunction() 

它只是恰巧memberFunction已添加到类通过包级扩展功能

fun ClassFromAnotherLibrary.memberFunction() : Foo { 
    val mapper = jacksonObjectMapper() 
    return mapper.readValue(this.serializedFoo, Foo::class.java) 
} 

我的包现在我想写的serviceFunction测试,但我想嘲笑了memberFunction电话(我有单独的测试为)。

所以在我的Mockito JUnit测试,我做了以下

val service = Service() 
val mockClassFromAnotherLibrary = mock<ClassFromAnotherLibrary>() 
val mockFoo = mock<Foo>() 

whenever(mockClassFromAnotherLibrary.memberFunction()) 
    .thenReturn(mockFoo) 

service.serviceFunction(mockClassFromAnotherLibrary) 

我预计memberFunction的实际执行情况将永远不会被调用,而我的模拟会拦截任何企图调用它,而不是回报我的mockFoo

什么实际上发生是whenever设置模拟出的方法被调用底层功能,造成NullPointerExceptionmapper尝试读取serializedFoo(这当然是空的)。

我的问题是:为什么地球上真的memberFunction被执行?我是Mockito和Kotlin的新手,但过去曾使用Jasmine(用于JS)和Spock(用于Groovy/Java)测试,并且在这两种框架中嘲笑对象时,从未实际执行任何嘲笑 - out功能(我知道)。

我已经能够通过使ClassFromAnotherLibrary我试图嘲弄有一个interface,我嘲笑而不是类似问题的解决这个在过去,但

  1. 感觉哈克和
  2. 是不是在这种情况下(这不是我的课进行编辑,它是从另一个库来)

供参考,这是相关gradle这个依赖性我的项目是使用一个选项:

compile "com.fasterxml.jackson.module:jackson-module-kotlin:2.8.9" 
compile "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.8.9" 
compile "com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.8.9" 

testCompile 'junit:junit:4.12' 
testCompile "org.jetbrains.kotlin:kotlin-test:1.1.4-3" 
testCompile "org.jetbrains.kotlin:kotlin-test-junit:1.1.4-3" 
testCompile "com.nhaarman:mockito-kotlin:1.3.0" 
testCompile "org.mockito:mockito-inline:2.8.47" 

我还建立了一套MockMaker文件在我test/resources文件夹,使mock-maker-inline,虽然我不完全理解它是一个可能实现的目标(看到一个关于它的尖端here

由于任何Kocklin/Mockito

回答

2

扩展函数不过是一个常规的Java静态方法,据我所知,Mockito不能嘲笑静态方法。

+0

你是说Kotlin扩展函数(可以访问'this')是作为一个类静态函数实现的吗?这是否意味着它也获得了一个隐含的论点(这个)? 我不知道Mockito不能嘲笑静态方法,但很高兴知道! –

+1

是的。确实如此。 –

+0

感谢您指出这一点!对于任何不愿意采用拉法尔的话的人(我总是喜欢有多个来源),这里有一篇文章解释: https://android.jlelse.eu/the-ugly-truth-about-扩展函数合科特林-486ec49824f4 –