如何模拟Kotlin单身物件?

给定一个Kotlin单身对象和一个叫它的方法的乐趣

object SomeObject { fun someFun() {} } fun callerFun() { SomeObject.someFun() } 

有没有办法模拟调用SomeObject.someFun()

只是让你的对象实现一个接口,比你可以嘲笑你反对任何嘲笑库。 这里是Junit + Mockito + Mockito-Kotlin的例子:

 import com.nhaarman.mockito_kotlin.mock import com.nhaarman.mockito_kotlin.whenever import org.junit.Assert.assertEquals import org.junit.Test object SomeObject : SomeInterface { override fun someFun():String { return "" } } interface SomeInterface { fun someFun():String } class SampleTest { @Test fun test_with_mock() { val mock = mock<SomeInterface>() whenever(mock.someFun()).thenReturn("42") val answer = mock.someFun() assertEquals("42", answer) } } 

或者,如果你想在模拟SomeObject内部callerFun

 import com.nhaarman.mockito_kotlin.mock import com.nhaarman.mockito_kotlin.whenever import org.junit.Assert.assertEquals import org.junit.Test object SomeObject : SomeInterface { override fun someFun():String { return "" } } class Caller(val someInterface: SomeInterface) { fun callerFun():String { return "Test ${someInterface.someFun()}" } } // Example of use val test = Caller(SomeObject).callerFun() interface SomeInterface { fun someFun():String } class SampleTest { @Test fun test_with_mock() { val mock = mock<SomeInterface>() val caller = Caller(mock) whenever(mock.someFun()).thenReturn("42") val answer = caller.callerFun() assertEquals("Test 42", answer) } } 

除非您愿意并能够更改代码,否则操作字节代码的答案是否定的。 模拟callerFunSomeObject.someFun()的调用的最直接的方式(以及我推荐的方式SomeObject.someFun()是提供一些方法来将其滑动为模拟对象。

例如

 object SomeObject { fun someFun() {} } fun callerFun() { _callerFun { SomeObject.someFun() } } internal inline fun _callerFun(caller: () -> Unit) { caller() } 

这里的想法是改变你愿意改变的东西。 如果你确定你需要一个单例和一个顶级函数作用于这个单例,那么如上所示,为了使顶级函数可测试而不改变它的公共签名,就是将它的实现移动到一个internal函数这允许滑倒模拟。