kotlin und ArgumentCaptor - IllegalStateException
Ich habe ein problem mit der Aufnahme das argument Klasse über ArgumentCaptor. Meine Testklasse sieht wie folgt aus:
@RunWith(RobolectricGradleTestRunner::class)
@Config(sdk = intArrayOf(21), constants = BuildConfig::class)
class MyViewModelTest {
@Mock
lateinit var activityHandlerMock: IActivityHandler;
@Captor
lateinit var classCaptor: ArgumentCaptor<Class<BaseActivity>>
@Captor
lateinit var booleanCaptor: ArgumentCaptor<Boolean>
private var objectUnderTest: MyViewModel? = null
@Before
fun setUp() {
initMocks(this)
...
objectUnderTest = MyViewModel(...)
}
@Test
fun thatNavigatesToAddListScreenOnAddClicked(){
//given
//when
objectUnderTest?.addNewList()
//then
verify(activityHandlerMock).navigateTo(classCaptor.capture(), booleanCaptor.capture())
var clazz = classCaptor.value
assertNotNull(clazz);
assertFalse(booleanCaptor.value);
}
}
Wenn ich den test ausführen, wird folgende Ausnahme ausgelöst:
java.lang.IllegalStateException: classCaptor.capture() darf nicht null sein
Ist es möglich mit argument Entführer in kotlin?
=========
UPDATE 1:
Kotlin: 1.0.0-beta-4584
Mockito: 1.10.19
Robolectric: 3.0
=========
UPDATE 2:
Stacktrace:
java.lang.IllegalStateException: classCaptor.capture() must not be null
at com.example.view.model.ShoplistsViewModelTest.thatNavigatesToAddListScreenOnAddClicked(ShoplistsViewModelTest.kt:92)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
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 org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:251)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:188)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54)
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.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:152)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
- Habe gerade versucht das Beispiel und es funktioniert Prima. Welche Versionen von kotlin, mockito und roboelectric, die Sie verwenden?
- Vielen Dank für die überprüfung. Ich habe aktualisiert die Frage. Welche Versionen hast du probiert?
- Nur geprüft das Beispiel von gist und es funktioniert mit den Versionen, die Sie aufgeführt haben. Scheint, dass dein code etwas anders. Kannst du einen stacktrace?
- Ich habe den stacktrace. Leider scheint es nicht sehr hilfreich.
- Du hast Recht, es funktioniert nicht. Es scheint seltsam, aber, dass Sie
RobolectricTestRunner
im stack-trace, obwohl dieRunWith
sagtRobolectricGradleTestRunner
- Könnte das problem sein, dass der Rückgabewert von classCaptor.capture() ist null? Kotlin dann denkt, dass die Unterschrift von IActivityHandler#navigateTo(Class, Boolean) kann nicht zulassen, dass ein null-argument?
- Ja, das ist es. Du hast Recht. Ich habe nicht bemerkt, dass die navigateTo-Methode akzeptiert nur nicht-null-Werte. Wenn ich geändert singature von navigateTo-Methode dieses: Spaß navigateTo(clazz: Class<out BaseActivity>?, closeCurrent: Boolean), dann Beispiel funktioniert gut. Wenn Sie möchten, bitte fügen Sie einer Antwort auf diese Frage, also falls jemand anderes das selbe problem hat kann er die Lösung finden.
- Sehen Rampen Kommentar über die Entsendung eine Antwort.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Den Rückgabewert
classCaptor.capture()
ist null, aber die Signatur vonIActivityHandler#navigateTo(Class, Boolean)
nicht erlauben, ein null-argument.Den mockito-kotlin Bibliothek bietet unterstützende Funktionen, um dieses problem zu lösen.
verify
zu com.nhaarman.mockito_kotlin.stellen Sie sicher, problem verschwunden.com.nhaarman.mockitokotlin2.capture<MyType>(argumentCaptor)
Für einige ist es eine Datei, MockitoKotlinHelpers.kt zur Verfügung gestellt von Google in die Android-Architektur, repo. Es bietet eine bequeme Möglichkeit zum call erfassen.. einfach anrufen
verify(activityHandlerMock).navigateTo(capture(classCaptor), capture(booleanCaptor))
fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
Dann im test:val userCacheCaptor = ArgumentCaptor.forClass(User::class.java) Mockito.verify(userCache, Mockito.times(1)).set(Mockito.anyString(), capture(userCacheCaptor))
der Fehler ist:java.lang.IllegalStateException: capture(userCacheCaptor) must not be null
Mockito.verify(eq(userCache), Mockito.times(1)).set(Mockito.anyString(), capture(userCacheCaptor) as User)
. Sorry für die späte Antwort@Captor private lateinit var snackbarManagerArgumentCaptor: ArgumentCaptor<ShowSnackbarEvent>
und dann die Helferverify(snackbarManager).show(capture(snackbarManagerArgumentCaptor))
.Verwenden kotlin-mockito https://mvnrepository.com/artifact/com.nhaarman/mockito-kotlin/1.5.0 als Abhängigkeit-und sample-code wie unten geschrieben :
Laut diese Lösung meine Lösung hier:
Wie gesagt um CoolMind in den Kommentar, müssen Sie zunächst gradle import für Kotlin-Mockito und dann shift alle Ihre Importe zu verwenden diese Bibliothek. Ihre Importe werden jetzt wie folgt Aussehen:
Dann Ihre test-Klasse wird so etwas wie dieses:
Kam hier nach der kotlin-Mockito-Bibliothek hat auch nicht geholfen.
Erstellt habe ich eine Lösung mit der spiegelung.
Es ist eine Funktion, welche Ausschnitte das argument der verspottet-Objekt früher:
Verwendung:
(Sagen wir ich habe verspottet mein repository getestet und ein viewModel. Nach dem Aufruf der viewModel "update ()" - Methode mit einem MenuObject Objekt, ich möchte aber sicherstellen, dass die MenuObject heißt eigentlich auf das repository ist "updateMenuObject ()" - Methode:
Schreiben Sie ein wrapper über argument captor