在 Kotlin 使用 Mockito 有可能吗?

我面临的问题是 Matchers.anyObject()返回 null。当用于模拟只接受非空类型的方法时,它会引发“应该不为空”异常。

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

模仿方法:

public open fun login(userCredentials: UserCredentials): Response
48309 次浏览

There are two possible workarounds:

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 { ... }
}

The other workaround is

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


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

Here is some more discussion on this topic, where the workaround is first suggested.

I use verify a lot to make sure the parameters passed to a function are also correct.

To do this, and still avoid the NPE you can use kotlin's elvis operator. for example: verify(mock).func(same(my_obj) ?: my_obj)

This way, mockito is satisfied because it actually verifies the variable, and kotlin is satisfied because we pass a non null object.

Another thing I stumbled upon was the mockito-kotlin library which solves exactly this issue https://github.com/nhaarman/mockito-kotlin

You can use the following helper functions to use Mockito's any(), eq() and capture() matchers in Kotlin:

/**
* 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()

See MockitoKotlinHelpers.kt from the Android Architecture Blueprints repository by Google.

For those who need typed any(type: Class<T>)

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

This would work and the type check also happens!

it just need to return a nonnull result when you use Mockito.any();

Mockito.any() ?: 0
Mockito.any() ?: HashMap<Int,Int>()
Mockito.any() ?: {}

...

To extend on the answer provided by @makovkastar, you can provide a nullable or non-nullable Matcher like this:

/**
* 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)