#android #junit #mockito #mockk
Вопрос:
Я пытаюсь написать модульный тест для своей модели представления с помощью Mockk.
@Test
fun `When loading the ResponseViewState isLoading`() {
val observer = spyk<Observer<ResponseViewState>>(Observer { })
puppiesViewModel.status_.observeForever(observer)
every {
fetchPuppiesUseCase.fetchPuppies()
} returns
Observable.just(Resource.Loading)
puppiesViewModel.fetchPuppies()
val slot = slot<ResponseViewState>()
verify { observer.onChanged(capture(slot)) }
assert(slot.captured.isLoading())
verify { fetchPuppiesUseCase.fetchPuppies() }
}
Ошибка возникает, когда я создаю наблюдателя с помощью spyk.
val observer = spyk<Observer<ResponseViewState>>(Observer { })
Ошибка, которую я получаю, заключается в следующем
java.lang.NoClassDefFoundError: com/example/tink/PuppiesViewModelTest$Lambda$61/0x0000000800176840
at jdk.internal.reflect.GeneratedSerializationConstructorAccessor4.newInstance(Unknown Source)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:481)
at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:48)
at io.mockk.proxy.jvm.ObjenesisInstantiator.instanceViaObjenesis(ObjenesisInstantiator.kt:75)
at io.mockk.proxy.jvm.ObjenesisInstantiator.instance(ObjenesisInstantiator.kt:42)
at io.mockk.proxy.jvm.ProxyMaker.instantiate(ProxyMaker.kt:75)
at io.mockk.proxy.jvm.ProxyMaker.proxy(ProxyMaker.kt:42)
at io.mockk.impl.instantiation.JvmMockFactory.newProxy(JvmMockFactory.kt:34)
at io.mockk.impl.instantiation.AbstractMockFactory.newProxy$default(AbstractMockFactory.kt:29)
at io.mockk.impl.instantiation.AbstractMockFactory.spyk(AbstractMockFactory.kt:102)
at com.example.tink.PuppiesViewModelTest.createObserver(PuppiesViewModelTest.kt:99)
at com.example.tink.PuppiesViewModelTest.given loading state, when fetchPuppies called, then isLoading return true(PuppiesViewModelTest.kt:40)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
Caused by: java.lang.ClassNotFoundException: com.example.tink.PuppiesViewModelTest$Lambda$61.0x0000000800176840
Есть идеи, как исправить или, может быть, даже лучший подход к тестированию?
Комментарии:
1. Столкнувшись с той же ошибкой … у кого-нибудь была идея?
Ответ №1:
Похоже, что изменение относится к Kotlin и было внесено в версии 1.5. Изменение, KT-44912, относится к тому, как компилятор Kotlin генерирует анонимный класс, реализующий интерфейс SAM.
Вы можете легко проверить это, изменив версию Kotlin на 1.4.32 (последняя версия 1.4.X).
Простым решением было бы изменить ваш код на следующий:
val observer = createMockObserver()
@Suppress("ObjectLiteralToLambda") fun createMockObserver(): Observer<ResponseViewState> { val observer = object : Observer<ResponseViewState> { override fun onChanged(t: ResponseViewState?) { } } return spyk<Observer<ResponseViewState>>(observer) }
В качестве альтернативы вы можете заставить компилятор Kotlin использовать анонимное поколение классов до 1.5, добавив следующее в свой build.gradle
android
блок:
afterEvaluate { compileDebugUnitTestKotlin { kotlinOptions { freeCompilerArgs = [ '-Xsam-conversions=class', ] } } }
Комментарии:
1. Таким образом, ожидается, что мы не сможем использовать этот способ в последней версии kotlin, или это что-то, что они исправят в будущем ?