Ist es möglich, Mockito in Kotlin zu verwenden?

78

Das Problem, mit dem ich konfrontiert bin, ist die Matchers.anyObject()Rückkehr null. Wenn eine Methode verspottet wird, die nur nicht nullfähige Typen akzeptiert, wird die Ausnahme "Sollte nicht null sein" ausgelöst.

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

Verspottete Methode:

public open fun login(userCredentials: UserCredentials): Response
atok
quelle
2
Auf einer Kotlin-Community-Website wird diskutiert, wie dieses Problem vermieden werden kann.
Schauen
1
Vielen Dank. Scheint, als ob devnet.jetbrains.com von Google nicht sehr gut indiziert ist.
Atok

Antworten:

75

Es gibt zwei mögliche Problemumgehungen:

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

Die andere Problemumgehung ist

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

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

Hier finden Sie weitere Diskussionen zu diesem Thema, in denen zunächst die Problemumgehung vorgeschlagen wird.

Sergey Mashkov
quelle
6
Ich glaube, SO bittet Sie freundlich, den Inhalt des Links auch in Ihrer Antwort zu replizieren, damit diese Antwort immer noch nützlich ist, falls der Link jemals ausfällt.
Greg Kopff
1
Leider scheint diese Problemumgehung in 1.0.0-beta-4584 nicht mehr zu funktionieren : kotlin.TypeCastException: null cannot be cast to non-null type X.
Nhaarman
@nhaarman funktioniert perfekt für mich, könnten Sie mich bitte auf den genauen Fall hinweisen?
Sergey Mashkov
3
Es funktioniert nicht auf Kotlin 1.2.40. Gibt es keine andere Problemumgehung?
Amir Ziarati
@nhaarman Kotlin 1.3.11, Mockito 2.7.12, Kotlin Mockito 1.5.0, Januar 2019: Problemumgehung 1 ... nun, es funktioniert. Mein Anwendungsfall liegt innerhalb der angegebenen / wann-Klausel.
Milosmns
41

Für diejenigen, die getippt werden müssen any(type: Class<T>)

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

Dies würde funktionieren und die Typprüfung findet auch statt!

Shamm
quelle
4
Es ist möglich zu vermeiden, den ClassName :: class.java im Argument mit den reifizierten Argumenten zu übergeben:inline fun <reified T> anyNonNull(): T = Mockito.any<T>(T::class.java)
Thales Pupo Araujo
26

Sie können die folgenden Hilfsfunktionen verwenden, um Mockitos Matcher any (), eq () und capture () in Kotlin zu verwenden:

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

Siehe MockitoKotlinHelpers.kt aus dem Android Architecture Blueprints-Repository von Google.

Makovkastar
quelle
2
Es sieht so aus, als ob die URL verschoben wurde zu: github.com/googlesamples/android-architecture/blob/…
Surekha
Vielen Dank! Funktioniert auch mit der neuesten Version von Mockito (v3.3.3) und Kotlin (v1.3.72)
Fatmajk
10

Ich benutze verifyviel, um sicherzustellen, dass die an eine Funktion übergebenen Parameter auch korrekt sind.

Um dies zu tun und trotzdem die NPE zu vermeiden, können Sie den elvis-Operator von kotlin verwenden. zum Beispiel: verify(mock).func(same(my_obj) ?: my_obj)

Auf diese Weise ist mockito zufrieden, weil es die Variable tatsächlich überprüft, und kotlin ist zufrieden, weil wir ein Nicht-Null-Objekt übergeben.

Eine andere Sache, auf die ich gestoßen bin, war die Mockito-Kotlin-Bibliothek, die genau dieses Problem löst: https://github.com/nhaarman/mockito-kotlin

Maxandron
quelle
1

Es muss nur ein nicht null Ergebnis zurückgegeben werden, wenn Sie verwenden Mockito.any().

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

...

max li
quelle
0

Um die Antwort von @makovkastar zu erweitern, können Sie einen nullbaren oder nicht nullbaren Matcher wie folgt bereitstellen:

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