可以在 Kotlin 中使用 Mockito 吗?

Is it possible to use Mockito in Kotlin?

我面临的问题是 Matchers.anyObject() returns null。当用于模拟只接受不可为空类型的方法时,它会导致抛出 "Should not be null" 异常。

`when`(mockedBackend.login(anyObject())).thenAnswer { invocationOnMock -> someResponse }

模拟方法:

public open fun login(userCredentials: UserCredentials): Response

有两种可能的解决方法:

private fun <T> anyObject(): T {
    Mockito.anyObject<T>()
    return uninitialized()
}

private fun <T> uninitialized(): T = null as T

@Test
fun myTest() {
    `when`(mockedBackend).login(anyObject())).thenAnswer { ... }
}

另一个解决方法是

private fun <T> anyObject(): T {
    return Mockito.anyObject<T>()
}

@Test
fun myTest() {
    `when`(mockedBackend).login(anyObject())).thenAnswer { ... }
}

这里是关于这个主题的some more discussion,其中首先提出了解决方法。

我经常使用 verify 来确保传递给函数的参数也是正确的。

要做到这一点,并且仍然避免 NPE,您可以使用 kotlin 的 elvis 运算符。 例如: verify(mock).func(same(my_obj) ?: my_obj)

这样,mockito 就满足了,因为它实际验证了变量,kotlin 就满足了,因为我们传递了一个非空对象。

我偶然发现的另一件事是 mockito-kotlin 库,它正好解决了这个问题 https://github.com/nhaarman/mockito-kotlin

您可以使用以下辅助函数在 Kotlin 中使用 Mockito 的 any()、eq() 和 capture() 匹配器:

/**
 * Returns Mockito.eq() as nullable type to avoid java.lang.IllegalStateException when
 * null is returned.
 *
 * Generic T is nullable because implicitly bounded by Any?.
 */
fun <T> eq(obj: T): T = Mockito.eq<T>(obj)

/**
 * Returns Mockito.any() as nullable type to avoid java.lang.IllegalStateException when
 * null is returned.
 */
fun <T> any(): T = Mockito.any<T>()

/**
 * Returns ArgumentCaptor.capture() as nullable type to avoid java.lang.IllegalStateException
 * when null is returned.
 */
fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()

请参阅 Google 的 Android 架构蓝图存储库中的 MockitoKotlinHelpers.kt

需要打字的人any(type: Class<T>)

    private fun <T> any(type: Class<T>): T = Mockito.any<T>(type)

这会起作用,类型检查也会发生!

当您使用 Mockito.any();

时,它只需要 return 一个非空结果
Mockito.any() ?: 0
Mockito.any() ?: HashMap<Int,Int>()
Mockito.any() ?: {}

...

要扩展@makovkastar 提供的答案,您可以像这样提供可为空或 non-nullable 匹配器:

/**
 * Matcher that returns null
 */
private inline fun <reified T> any(): T = Mockito.any<T>()

/**
 * Matcher never returns null
 */
private inline fun <reified T> any(type: Class<T>): T = Mockito.any(type)