可以在 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)
我面临的问题是 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()
;
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)