Albert Gao
Albert Gao

Reputation: 3769

How to mock a module wide extension method with mockito?

This is the method to test:
It gets an URL and return a json after sending a GET request. It is a plain function which sits in a package rather than a method from a class. Same case for the extension method below.

fun getJson (url: String): String {
    val connection = URL(url).openConnection() as HttpURLConnection
    connection.requestMethod = "GET"
    return connection.getResult()
}

This is the extension method:
It will start connecting and read from result stream.

internal fun HttpURLConnection.getResult(charset: Charset = Charsets.UTF_8): String {
    this.connect()
    return this.inputStream.bufferedReader(charset).use { it.readText() }
}

This is the test case:
I tried to mock the HttpURLConnection that is about to be used here and call the original method, then just call the method and assert whether the mock has been set with the expected value.

class Spike {
    @Test
    fun test_getJson() {
        val expectedResult = "{ok: true}"
        val mockConnection = mock(HttpURLConnection::class.java)
        Mockito.`when`(mockConnection.getResult()).thenReturn(expectedResult)

        getJson("http://www.google.com")

        assertEquals("GET", mockConnection.requestMethod)
        assertEquals("http://www.google.com", mockConnection.url.host)
    }
}

This is the error

java.lang.IllegalStateException: this.inputStream must not be null at my.spike.pack.http.UtilsKt.getResult(utils.kt:45)

It just like the mock is not working.

How to solve this without changing the signature of the getJson function?

Upvotes: 0

Views: 1390

Answers (2)

Rafal G.
Rafal G.

Reputation: 4432

This will not work because of the way Kotlin extension methods are implemented on the class / bytecode level.

What you see in source code is HttpURLConnection.getResult but on the class/bytecode level there is another file created with a static method: public final static getResult(HttpURLConnection, Charset).

Mockito cannot mock static methods. If you really have to mock one, then I think PowerMock is capable of doing that.

Edit: If you have a module wide function then it is also generated on a class. Assuming you have a file StreamFunctions.kt with a function: doSomething then, there will be (by default) generated class StreamFunctionsKt with a static function doSomething. More details can be found here: https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html

Upvotes: 1

asm0dey
asm0dey

Reputation: 2931

That should be as easy as

    Mockito.`when`(mockConnection.inputStream).thenReturn(ByteArrayInputStream("test".toByteArray()))

Upvotes: 0

Related Questions