2017-10-11 3 views
0

Je travaille sur un pot de Kotlin où je tente de se moquer d'une entrée à une fonctionMockito Mocks Behaving Comme Spies: Kotlin

class MyService 
fun serviceFunction(input: ClassFromAnotherLibrary): Output { 
    val foo = input.memberFunction() 

Il se trouve que memberFunction a été ajouté à cette catégorie dans mon paquet via une fonction d'extension au niveau du package

fun ClassFromAnotherLibrary.memberFunction() : Foo { 
    val mapper = jacksonObjectMapper() 
    return mapper.readValue(this.serializedFoo, Foo::class.java) 
} 

maintenant, je veux écrire un test pour le serviceFunction, mais je veux railler sur l'appel memberFunction (je tests séparés pour cela).

Donc, dans mon test Mockito JUnit, je fais ce qui suit

val service = Service() 
val mockClassFromAnotherLibrary = mock<ClassFromAnotherLibrary>() 
val mockFoo = mock<Foo>() 

whenever(mockClassFromAnotherLibrary.memberFunction()) 
    .thenReturn(mockFoo) 

service.serviceFunction(mockClassFromAnotherLibrary) 

j'attendre à ce que la mise en œuvre effective de de memberFunction serait jamais appelé, et que ma maquette intercepteraient toute tentative de l'appeler et au lieu retour mon mockFoo.

Ce qui est en fait passe est la configuration whenever pour se moquer de la méthode est appeler la fonction sous-jacente, provoquant une NullPointerException lorsque les mapper essaie de lire serializedFoo (ce qui est évidemment nulle).

Ma question est: pourquoi diable est le vrai memberFunction en cours d'exécution ?? Je suis nouveau sur Mockito et Kotlin, mais j'ai utilisé Jasmine (pour JS) et Spock (pour Groovy/Java) dans le passé, et en se moquant d'un objet dans ces deux frameworks jamais exécuter jamais mocked- hors fonction (que je suis au courant).

Je suis en mesure de travailler sur des questions similaires à cela dans le passé en faisant le ClassFromAnotherLibrary que je suis en train de se moquer avoir un interface que je me moque au lieu, mais que

  1. Paraît aki et
  2. est pas une option dans ce cas (ce n'est pas ma classe à modifier, il vient d'une autre bibliothèque)

pour référence, ce sont les gradle pertinentes dépendances mon projet utilise:

compile "com.fasterxml.jackson.module:jackson-module-kotlin:2.8.9" 
compile "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.8.9" 
compile "com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.8.9" 

testCompile 'junit:junit:4.12' 
testCompile "org.jetbrains.kotlin:kotlin-test:1.1.4-3" 
testCompile "org.jetbrains.kotlin:kotlin-test-junit:1.1.4-3" 
testCompile "com.nhaarman:mockito-kotlin:1.3.0" 
testCompile "org.mockito:mockito-inline:2.8.47" 

J'ai également mis en place un fichier MockMaker dans mon dossier test/resources pour permettre mock-maker-inline, bien que je ne comprends pas tout à fait ce qu'il est que peut accomplir (vu une pointe à ce sujet here)

Merci à tout Kotlin/Mockito

Répondre

2

Les fonctions d'extension ne sont rien d'autre qu'une méthode statique standard de Java et, autant que je m'en souvienne, Mockito ne peut pas se moquer des méthodes statiques.

+0

Vous dites qu'une fonction d'extension Kotlin (qui a accès à 'this') est implémentée comme une fonction statique de classe sous le capot? Est-ce que cela veut dire que c'est aussi un argument implicite (ceci)? Je ne savais pas que Mockito ne pouvait pas se moquer des méthodes statiques, bon à savoir! –

+1

Oui. Exactement comme ça. –

+0

Merci d'avoir signalé cela!Pour tous ceux qui ne veulent pas prendre la parole de Rafal (j'aime toujours avoir plusieurs sources), voici un post expliquant: https://android.jlelse.eu/the-ugly-truth-about- extension-fonctions-en-kotlin-486ec49824f4 –