【发布时间】:2018-03-23 10:59:02
【问题描述】:
我正在开发一个 kotlin jar,我试图在其中模拟函数的输入
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 设置来模拟方法正在调用底层函数,当mapper 尝试读取时导致NullPointerException serializedFoo(当然是 null)。
我的问题是:到底为什么真正的 memberFunction 会被执行? 我是 Mockito 和 Kotlin 的新手,但我使用过 Jasmine(用于 JS)和 Spock(用于 Groovy / Java)过去的测试,并在这两个框架中模拟出一个对象永远不会真正执行任何模拟出的函数(我知道)。
我过去可以通过使我尝试模拟的ClassFromAnotherLibrary 有一个我模拟的interface 来解决与此类似的问题,但是
- 感觉很老套,而且
- 在这种情况下不是一个选项(这不是我要编辑的课程,它来自另一个库)
作为参考,这些是我的项目正在使用的相关 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"
我还在我的test/resources 文件夹中设置了一个MockMaker 文件以启用mock-maker-inline,尽管我并不完全理解它可能会完成什么(看到了关于它的提示here)
感谢 Kotlin/Mockito
【问题讨论】: