How to mock a Singleton Kotlin object?

Given the Singleton Kotlin object and the pleasure calling its method

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

Is there any way to make fun of calling SomeObject.someFun() ?

+21
source share
5 answers

Just create an object that implements the interface, than you can mock the object with any mocking library. Here is an 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 you want to 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) } } 
+12
source

There is a very good library for mocking Kotlin - Mockk , which allows you to make fun of objects exactly the way you want.

As of this documentation:


Objects can be converted to layouts as follows:

 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 go 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 the limitations of the Kotlin language, you can create new instances of objects if you need to check the logic:

 val newObjectMock = mockk<MockObj>() 
+18
source

You can mock an object without any additional library using class delegates.

Here is my suggestion

 val someObjectDelegate : SomeInterface? = null object SomeObject: by someObjectDelegate ?: SomeObjectImpl object SomeObjectImpl : SomeInterface { fun someFun() { println("SomeObjectImpl someFun called") } } interface SomeInterface { fun someFun() } 

In your tests, you can set a delegate object that will change behavior, otherwise it will use it in a real implementation.

 @Beofre fun setUp() { someObjectDelegate = object : SomeInterface { fun someFun() { println("Mocked function") } } // Will call method from your delegate SomeObject.someFun() } 

Of course, the above names are bad, but for example, this shows the purpose.

After initializing SomeObject, the delegate will process all functions.
You can find more in the official documentation.

+7
source

In addition to using the Mockk library, which is quite convenient, you could mock an object simply with Mockito and reflection. A Kotlin object is just an ordinary Java class with a private constructor and a static INSTANCE field, with reflection you can replace the INSTANCE value INSTANCE a mocked object. After the test, the original must be restored so that the change does not affect other tests.

Using Mockito Kotlin (add extension configuration as described here to make fun of the final classes):

 testCompile "com.nhaarman:mockito-kotlin:1.5.0" 

The first pleasure is to replace the value of the INSTANCE static field in the object class and return the previous value

 fun <T> replaceObjectInstance(clazz: Class<T>, newInstance: T): T { if (!clazz.declaredFields.any { it.name == "INSTANCE" && it.type == clazz && Modifier.isStatic(it.modifiers) }) { throw InstantiationException("clazz ${clazz.canonicalName} does not have a static " + "INSTANCE field, is it really a Kotlin \"object\"?") } val instanceField = clazz.getDeclaredField("INSTANCE") val modifiersField = Field::class.java.getDeclaredField("modifiers") modifiersField.isAccessible = true modifiersField.setInt(instanceField, instanceField.modifiers and Modifier.FINAL.inv()) instanceField.isAccessible = true val originalInstance = instanceField.get(null) as T instanceField.set(null, newInstance) return originalInstance } 

Then you could have some fun creating a mock instance of object and replace the original value with the mocked one, returning the original so it could be reset later

 fun <T> mockObject(clazz: Class<T>): T { val constructor = clazz.declaredConstructors.find { it.parameterCount == 0 } ?: throw InstantiationException("class ${clazz.canonicalName} has no empty constructor, " + "is it really a Kotlin \"object\"?") constructor.isAccessible = true val mockedInstance = spy(constructor.newInstance() as T) return replaceObjectInstance(clazz, mockedInstance) } 

Add some Kotlin sugar

 class MockedScope<T : Any>(private val clazz: Class<T>) { fun test(block: () -> Unit) { val originalInstance = mockObject(clazz) block.invoke() replaceObjectInstance(clazz, originalInstance) } } fun <T : Any> withMockObject(clazz: Class<T>) = MockedScope(clazz) 

And finally, given the object

 object Foo { fun bar(arg: String) = 0 } 

You can test it this way.

 withMockObject(Foo.javaClass).test { doAnswer { 1 }.whenever(Foo).bar(any()) Assert.assertEquals(1, Foo.bar("")) } Assert.assertEquals(0, Foo.bar("")) 
+4
source

Manipulating byte code is not enough, there is no answer if you do not want and cannot change the code. The easiest way (and the way I would recommend) to make fun of calling callerFun on SomeObject.someFun() is to provide some way to skip its object layout.

eg.

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

The idea here is to change what you are ready to change. If you are sure that you want one singleton and a top-level function operating on this singleton, then one of the ways, as shown above, is to make the top-level function a check without changing its public signature - move its implementation to internal , which allows you to slide the layout.

+1
source

All Articles