如何使用mockito模拟模块范围的扩展方法?

时间:2018-03-14 01:15:37

标签: unit-testing mocking kotlin mockito

这是测试的方法:
它获取一个URL并在发送GET请求后返回一个json。它是一个简单的函数,它位于包而不是类中的方法中。下面的扩展方法也是如此。

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

这是扩展方法:
它将开始连接并从结果流中读取。

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

这是测试用例:
我试图模拟即将使用的HttpURLConnection并调用原始方法,然后调用方法并断言模拟是否已设置为期望值。

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

这是错误

  

java.lang.IllegalStateException:this.inputStream不能为null   my.spike.pack.http.UtilsKt.getResult(utils.kt:45)

就像模拟不起作用一样。

如何在不更改getJson功能的签名的情况下解决此问题?

2 个答案:

答案 0 :(得分:1)

由于Kotlin扩展方法在类/字节码级别上实现的方式,这不起作用。

您在源代码中看到的是HttpURLConnection.getResult,但在类/字节码级别上,还有另一个使用静态方法创建的文件:public final static getResult(HttpURLConnection, Charset)

Mockito无法模拟静态方法。如果你真的需要模拟一个,那么我认为PowerMock能够做到这一点。

编辑: 如果你有一个模块范围的功能,那么它也是在一个类上生成的。假设您有一个带有函数StreamFunctions.kt的文件doSomething,那么(默认情况下)将生成具有静态函数StreamFunctionsKt的类doSomething。更多细节可以在这里找到:https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html

答案 1 :(得分:0)

这应该像

一样简单
    Mockito.`when`(mockConnection.inputStream).thenReturn(ByteArrayInputStream("test".toByteArray()))