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

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.


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!


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.


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


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() ?: {}

...


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)
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.