Mocking extension function in Kotlin

18,658

Solution 1

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

Solution 2

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)
}

Solution 3

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.

Share:
18,658

Related videos on Youtube

Romper
Author by

Romper

Updated on June 28, 2022

Comments

  • Romper
    Romper almost 2 years

    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?

    • nhaarman
      nhaarman almost 7 years
      Just like in Java, you want to avoid static methods like that. Static methods should usually be used as simple util functions. Extension functions are like static methods, so they should only be used as simple util functions. These functions should be so simple it is not needed or worth to mock them.
    • Sachin Chandil
      Sachin Chandil almost 7 years
      can you provide what have you tried till now?
    • GhostCat
      GhostCat almost 7 years
      Just wondering: are you still waiting for other answers; or is there something I could do to make my answer accept-worthy?
  • Kraiden
    Kraiden almost 7 years
    just for the next person, extension function signatures in java: class FilenameKt { public static ReturnType extensionName(Receiver receiver, Params otherParams)...
  • hmac
    hmac over 4 years
    does this work when the extension function has arguments? Verify seems to fail due to mismatching arguments (weirdly it seems to expect another argument, of type equal to the class you're extending)
  • Micer
    Micer almost 4 years
    Works prefectly, thanks! Note when using verify you need to use the one from Mockk library and not from Mockito. Since I had both in the same file, I solved it by creating import alias: import io.mockk.verify as verifyMockk
  • LeYAUable
    LeYAUable over 3 years
    This did not work for me, but a slightly different way did (adapted to the example): every { any<Obj>().extensionFunc() } returns 11 looks silly because now the result does not depend on parameters, but in my use-case it didn't have to and the other way was throwing errors.
  • typoerrpr
    typoerrpr over 3 years
    exactly what I was looking for!
  • Alfred Afutu
    Alfred Afutu about 3 years
    Works like a charm
  • VIN
    VIN over 2 years
    So you have to wrap the extension function in a class?