Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking extension function in Kotlin

How to mock Kotlin extension function using Mockito or PowerMock in tests? Since they are resolved statically should they be tested as static method calls or as non static?

like image 737
Romper Avatar asked Jun 06 '17 06:06

Romper


People also ask

What is Mockk Kotlin?

In Android, there are a lot of frameworks used for mocking in unit testing, such as PowerMock, Mockito, EasyMock, etc. MockK is definitely a better alternative to other mocking frameworks for Kotlin, the official development language for Android. Its main philosophy is first-class support for Kotlin features.

Can we use Mockito with Kotlin?

Mockito has been around since the early days of Android development and eventually became the de-facto mocking library for writing unit tests. Mockito and Mockk are written in Java and Kotlin, respectively, and since Kotlin and Java are interoperable, they can exist within the same project.

What is Mockk?

Mockk is a mocking framework built for Kotlin. Like Mockito, Mockk allows you to create and stub objects within your test code. Mocking objects allows you to test in isolation other objects. Any dependency of the object under test can be mocked to provide fixed conditions, thus ensuring specific and stable tests.

How do you verify in Mockk?

Inside the verification block (between the opening curly bracket { and closing curly bracket } ), you write the method you want to verify. { navigator. navigateTo("Park") } tells MockK to check if the navigateTo method on the navigator object was called with the argument "Park" .


4 Answers

I think MockK can help you.

It supports mocking extension functions too.

You can use it to mock object-wide extensions:

data class Obj(val value: Int)

class Ext {
    fun Obj.extensionFunc() = value + 5
}

with(mockk<Ext>()) {
    every {
        Obj(5).extensionFunc()
    } returns 11

    assertEquals(11, Obj(5).extensionFunc())

    verify {
        Obj(5).extensionFunc()
    }
}

If you extension is a module-wide, meaning that it is declared in a file (not inside class), you should mock it in this way:

data class Obj(val value: Int)

// declared in File.kt ("pkg" package)
fun Obj.extensionFunc() = value + 5

mockkStatic("pkg.FileKt")

every {
    Obj(5).extensionFunc()
} returns 11

assertEquals(11, Obj(5).extensionFunc())

verify {
    Obj(5).extensionFunc()
}

By adding mockkStatic("pkg.FileKt") line with the name of a package and file where extension is declared (pkg.File.kt in the example).

More info can be found here: web site and github

like image 59
Demigod Avatar answered Oct 20 '22 13:10

Demigod


First of all, Mockito knows nothing Kotlin specific language constructs. In the end, Mockito will have a look into the byte code. Mockito is only able to understand what it finds there and what looks like a Java language construct.

Meaning: to be really sure, you might want to use javap to deassemble the compiled classfiles to identify the exact names/signatures of the methods you want to mock.

And obviously: when that method is static, you have to user PowerMock, or JMockit; if not, you should prefer to with Mockito.

From a java point of view, you simply avoid mocking static stuff; but of course, things get really interesting, now that different languages with different ideas/concepts come together.

like image 26
GhostCat Avatar answered Oct 20 '22 14:10

GhostCat


Instance extension functions can be stubbed and verified like this with the help of mockito-kotlin:

data class Bar(thing: Int)

class Foo {
   fun Bar.bla(anotherThing: Int): Int { ... }
}

val bar = Bar(thing = 1)
val foo = mock<Foo>()

with(foo) {
  whenever(any<Bar>().bla(any()).doReturn(3)
}

verify(foo).apply {
  bar.bla(anotherThing = 2)
}
like image 44
Thomas Keller Avatar answered Oct 20 '22 15:10

Thomas Keller


I use mockk library.

For extension file write java name, like this:

@file:JvmName(name = "ExtensionUtils")

package myproject.extension

...

And for fast codding I created file with different extension mocks:

object FastMock {

    fun extension() = mockkStatic("myproject.extension.ExtensionUtils")

    fun listExtension() = mockkStatic("myproject.extension.ListExtensionUtils")

}

In test call this:

FastMock.listExtension()
every { itemList.move(from, to) } returns Unit
like image 27
SerjantArbuz Avatar answered Oct 20 '22 13:10

SerjantArbuz