给定科特林单对象,并调用它的方法如何模拟Kotlin单例对象?
object SomeObject {
fun someFun() {}
}
fun callerFun() {
SomeObject.someFun()
}
有没有一种方法来模拟来电SomeObject.someFun()
一个有趣?
给定科特林单对象,并调用它的方法如何模拟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)
}
}
操作字节码的缺点是答案是否定的,除非您愿意并且能够更改代码。以最直接的方式(以及我推荐的方式)模拟callerFun
对SomeObject.someFun()
的呼叫是提供某种方式将其滑入模拟对象。
例如
object SomeObject {
fun someFun() {}
}
fun callerFun() {
_callerFun { SomeObject.someFun() }
}
internal inline fun _callerFun(caller:() -> Unit) {
caller()
}
这里的想法是改变你愿意改变的东西。如果你确定你想要一个单例和一个顶级函数作用于这个单例,那么如上所示,为了使顶级函数可测试而不改变它的公共签名,将它的实现移动到一个函数internal
函数这允许滑倒模拟。
有用于科特林一个非常好的新的嘲弄库。它叫做Mockk。
它今天更新到版本1.7,它允许你模拟对象,完全相同的方式你想要的。
由于它的文档:
对象可以转化为嘲笑方式如下:
object MockObj {
fun add(a: Int, b: Int) = a + b
}
objectMockk(MockObj).use {
assertEquals(3, MockObj.add(1, 2))
every { MockObj.add(1, 2) } returns 55
assertEquals(55, MockObj.add(1, 2))
}
尽管科特林语言的限制,您可以创建,如果对象的新实例测试逻辑需要:
val newObjectMock = mockk<MockObj>()
您可以使用类代表来模拟没有任何额外库的对象。
这里是我的建议
val someObjectDelegate : SomeInterface? = null
object SomeObject: by someObjectDelegate ?: SomeObjectImpl
object SomeObjectImpl : SomeInterface {
fun someFun() {
println("SomeObjectImpl someFun called")
}
}
interface SomeInterface {
fun someFun()
}
在您的测试,你可以设置委托对象,这将改变人们的行为,否则将使用它的真正实施。
@Beofre
fun setUp() {
someObjectDelegate = object : SomeInterface {
fun someFun() {
println("Mocked function")
}
}
// Will call method from your delegate
SomeObject.someFun()
}
上述过程名是坏的,但是对于一个示例的目的示出了它的目的。
SomeObject初始化后,委托将处理所有的功能。
更多你可以找到官方documentation
这看起来像一个反模式...一个不应该在主代码中创建额外的类/接口只是为了测试的目的! – Kerooker
没有额外的类,只是接口。你应该这样做,因为这是在JVM上测试的最佳实践。 – IRus