Kotlin Android Mockito.verify not invoked obwohl Aufruf im Debug zu sehen

jokakilla

Lt. Junior Grade
Registriert
Dez. 2007
Beiträge
294
Hallo zusammen,
vielleicht kann mir hier ja jemand helfen. Ich habe kürzlich ein Android Projekt auf Kotlin portiert und kämpfe gerade mit den Tests.

Ich übergebe die Business Logik in Form eines Objekts an den Konstruktor vom Fragment. Der Test soll prüfen ob das Fragment beim onCreate die Initialisierungsmethode des Objektes aufruft.

Code:
@Test
fun nfcWriterInitializedOnCreate() {
    MockitoAnnotations.initMocks(this)
    val nfcWriterMock = Mockito.mock( NfcWriter::class.java )
    val fragmentWriteNfcTag = FragmentWriteNfcTag( "testTag", nfcWriterMock )
    mActivityRule.activity.supportFragmentManager
            .beginTransaction()
            .replace( R.id.viewFragmentContainer, fragmentWriteNfcTag, "" )
            .addToBackStack( fragmentWriteNfcTag.tag )
            .commitAllowingStateLoss()

    Mockito.verify( nfcWriterMock ).prepareNfc( anyOrNull() )
}

Im Debug Modus mit Breakpoints beim Mockito.verify und im Fragment.onCreate sieht man dass der prepareNfc Aufruf im onCreate erreicht wird und das NfcWriter Objekt auch exakt das gemockte ist. Der Aufruf müsste also eigentlich kommen aber Mockito scheint ihn nicht mitzubekommen. Da prepareNfc nichts zurück gibt muss ich den Aufruf auch nicht mit Mockito.when behandeln.

Fun-Fact: Baue ich hinter der Zeile in der der NfcWriter gemockt wird folgendes ein, schlägt der Test trotzdem fehl aber er bleibt beim Breakpoint bei println() stehen.
Mockito.when( nfcWriterMock.prepareNfc( anyOrNull() ) ).then {
println()
}

Hat jemand eine Idee? Kann das am DexOpener liegen den ich benutze damit die ganzen Kotlin Klassen, die ja final sind Mockbar werden?
androidTestImplementation 'com.github.tmurakami:dexopener:2.0.2'




2019-05-10 21:18:20.795 8619-8635/com.my.app E/TestRunner: failed: nfcWriterInitializedOnCreate(com.my.app.writeNfcTag.TestFragmentWriteNfcTag)
2019-05-10 21:18:20.796 8619-8635/com.my.app E/TestRunner: ----- begin exception -----
2019-05-10 21:18:20.803 8619-8635/com.my.app E/TestRunner: Wanted but not invoked:
nfcWriter.prepareNfc(<any>);
-> at com.my.app.writeNfcTag.TestFragmentWriteNfcTag.nfcWriterInitializedOnCreate(TestFragmentWriteNfcTag.kt:71)
Actually, there were zero interactions with this mock.

at com.my.app.writeNfcTag.TestFragmentWriteNfcTag.nfcWriterInitializedOnCreate(TestFragmentWriteNfcTag.kt:71)
at java.lang.reflect.Method.invoke(Native Method)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at androidx.test.internal.runner.junit4.statement.RunBefores.evaluate(RunBefores.java:80)
at androidx.test.rule.ActivityTestRule$ActivityStatement.evaluate(ActivityTestRule.java:531)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at androidx.test.ext.junit.runners.AndroidJUnit4.run(AndroidJUnit4.java:104)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at androidx.test.internal.runner.TestExecutor.execute(TestExecutor.java:56)
at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:388)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2145)
2019-05-10 21:18:20.803 8619-8635/com.my.app E/TestRunner: ----- end exception -----
 
Eine Möglichkeit ist im Debug zu prüfen ob wirklich das Mockobjekt gerufen wird (der Typ ist irgendwas mit Mockito) und nicht das echte Objekt (der echte NfcWriter).
 
Ich glaube ich habe die Ursache gerade gefunden. Die Signatur der PrepareNfc Methode sieht so aus:
fun prepareNfc( activity: Activity )

Dass heißt null als Parameter ist nicht erlaubt. Sowohl
Code:
Mockito.verify( nfcWriterMock ).prepareNfc( any() )
als auch
Code:
Mockito.verify( nfcWriterMock ).prepareNfc( anyOrNull() )
scheinen zu scheitern weil die Mockito Matcher immer null zurückgeben.

Baue ich in die Testklasse folgendes ein:
Code:
private fun <T> anyObject(): T {
    return Mockito.anyObject<T>()
}

und prüfe mit
Code:
Mockito.verify( nfcWriterMock ).prepareNfc( anyObject() )
klappt es.
Wirklich schön ist das aber nicht weil Mockito.anyObject<T>() als deprecated markiert ist.
 

Ähnliche Themen

Zurück
Oben