6

I am trying to write a unit test for my view model with help of 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() }
}

The error happens when I am creating the observer via spyk.

val observer = spyk<Observer<ResponseViewState>>(Observer { })

The error I am getting is

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

Any idea how to fix or maybe even a better approach for testing?

Mehdi Satei
  • 1,225
  • 9
  • 26

1 Answers1

6

It seems the change relates to Kotlin and was made at version 1.5. The change, KT-44912, relates to how the Kotlin compiler generates anonymous class implementing the SAM interface.

You can easily test this by changing your Kotlin version to 1.4.32 (latest 1.4.X).

An easy solution would be changing your code to the following:

 val observer = createMockObserver()
@Suppress("ObjectLiteralToLambda")
fun createMockObserver(): Observer<ResponseViewState> {
    val observer = object : Observer<ResponseViewState> {

        override fun onChanged(t: ResponseViewState?) { }
    }

    return spyk<Observer<ResponseViewState>>(observer)
}

Alternatively, you can force the Kotlin compiler to use the pre-1.5 anonymous class generation by adding the following to your build.gradle under the android block:

afterEvaluate {
    compileDebugUnitTestKotlin {
        kotlinOptions {
            freeCompilerArgs += [
                    '-Xsam-conversions=class',
            ]
        }
    }
}
vvbYWf0ugJOGNA3ACVxp
  • 1,086
  • 10
  • 23
  • 2
    So it is expected we cannot use that way on latest kotlin version or is it something they will fix in the future ? – Doni Jul 19 '21 at 04:27
  • thats what I am wondering as well, I recently ran into this issue and I do not know which option is better, opting for suppressing the ObjectLiteralToLambda warning or forcing the kotlin compiler to fall back to the pre 1.5 anonymous class generation. – jteichert Feb 24 '22 at 13:17