Given a Kotlin singleton object and a fun that call it's method
object SomeObject { fun someFun() {} } fun callerFun() { SomeObject.someFun() }
Is there a way to mock call to SomeObject.someFun()
?
If you are using Mockito 3.4. 0+, you may mock a singleton like the following, without PowerMock or other dependencies.
Using Singletons in Kotlin. By using the keyword object in your app, you're defining a singleton. A singleton is a design pattern in which a given class has only one single instance inside the entire app.
But in Kotlin, we need to use the object keyword. The object class can have functions, properties, and the init method. The constructor method is not allowed in an object so we can use the init method if some initialization is required and the object can be defined inside a class.
There's a very nice mocking library for Kotlin - Mockk, which allows you to mock objects, the exact same way you're desiring.
As of its documentation:
Objects can be transformed to mocks following way:
object MockObj { fun add(a: Int, b: Int) = a + b } mockkObject(MockObj) // aplies mocking to an Object assertEquals(3, MockObj.add(1, 2)) every { MockObj.add(1, 2) } returns 55 assertEquals(55, MockObj.add(1, 2))
To revert back use unmockkAll or unmockkObject:
@Before fun beforeTests() { mockkObject(MockObj) every { MockObj.add(1,2) } returns 55 } @Test fun willUseMockBehaviour() { assertEquals(55, MockObj.add(1,2)) } @After fun afterTests() { unmockkAll() // or unmockkObject(MockObj) }
Despite Kotlin language limits you can create new instances of objects if testing logic needs that:
val newObjectMock = mockk<MockObj>()
Just make you object implement an interface, than you can mock you object with any mocking library. Here example of 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) } }
Or in case if you want mock SomeObject
inside 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) } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With