MockK: return different result for different type parameter in generic function

Viewed 3214

I am trying to return different values for different type parameters in my generic function, but on some reason only one of the mocks is taken into account (the latest, as it seems). I have tried four different approaches, they all are listed below.

If you know that such behavior can be achieved with Mockito or any other mocking framework, please let me know too

import io.mockk.MockKAnnotations
import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.reactivex.Single
import org.junit.Before
import org.junit.Test
import retrofit2.Response

class MyTest {
    class A
    class B
    class MyClass() {
        fun <T> myMethod(callback: () -> Single<Response<T>>): Single<T> {
            error("")
        }
    }

    val a = A()
    val b = B()

    @MockK
    lateinit var myClass: MyClass

    @Before
    fun setUp() {
        MockKAnnotations.init(this)
    }

    @Test
    fun tmp() {
        every { myClass.myMethod<A>(any()) } returns (Single.just(a))
        every { myClass.myMethod<B>(any()) } returns (Single.just(b))
        myClass.myMethod<A> { Single.just(Response.success(a)) }.test().assertResult(a)
        myClass.myMethod<B> { Single.just(Response.success(b)) }.test().assertResult(b)
    }

    @Test
    fun tmp2() {
        every { myClass.myMethod(any<() -> Single<Response<A>>>()) } returns (Single.just(a))
        every { myClass.myMethod(any<() -> Single<Response<B>>>()) } returns (Single.just(b))
        myClass.myMethod<A> { Single.just(Response.success(a)) }.test().assertResult(a)
        myClass.myMethod<B> { Single.just(Response.success(b)) }.test().assertResult(b)
    }

    @Test
    fun tmp3() {
        every { myClass.myMethod(any<() -> Single<Response<A>>>()).hint(A::class) } returns (Single.just(a))
        every { myClass.myMethod(any<() -> Single<Response<B>>>()).hint(B::class) } returns (Single.just(b))
        myClass.myMethod<A> { Single.just(Response.success(a)) }.test().assertResult(a)
        myClass.myMethod<B> { Single.just(Response.success(b)) }.test().assertResult(b)
    }

    @Test
    fun tmp4() {
        every { myClass.myMethod<A>(any()).hint(A::class) } returns (Single.just(a))
        every { myClass.myMethod<B>(any()).hint(B::class) } returns (Single.just(b))
        myClass.myMethod<A> { Single.just(Response.success(a)) }.test().assertResult(a)
        myClass.myMethod<B> { Single.just(Response.success(b)) }.test().assertResult(b)
    }
}

The error that each of the methods show:


java.lang.AssertionError: Values at position 0 differ; expected: my.packagge.MyTest$A@130a0f66 (class: A) but was: my.packagge.MyTest$B@4c432866 (class: B) (latch = 0, values = 1, errors = 0, completions = 1)
Expected :my.packagge.MyTest$A@130a0f66 (class: A)
Actual   :my.packagge.MyTest$B@4c432866 (class: B) (latch = 0, values = 1, errors = 0, completions = 1)
<Click to see difference>


    at io.reactivex.observers.BaseTestConsumer.fail(BaseTestConsumer.java:189)
    at io.reactivex.observers.BaseTestConsumer.assertValues(BaseTestConsumer.java:545)
    at io.reactivex.observers.BaseTestConsumer.assertResult(BaseTestConsumer.java:796)
    at my.packagge.MyTest.tmp(MyTest.kt:35)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    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.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 org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
    at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
    at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)

Thanks in advance!

1 Answers

Try again. I'm not sure if there's a better way to do it.

class MyTest {
    class A
    class B
    class MyClass() {
        fun <T> myMethod(callback: () -> Single<Response<T>>): Single<T> {
            error("")
        }
    }

    val a = A()
    val b = B()

    @RelaxedMockK
    lateinit var myClass: MyClass

    @Before
    fun setUp() {
        MockKAnnotations.init(this)
    }

    @Test
    fun tmp() {
        every { myClass.myMethod<A>(any()) } returns (Single.just(a))
        myClass.myMethod<A> { Single.just(Response.success(a)) }.test().assertResult(a)

        every { myClass.myMethod<B>(any()) } returns (Single.just(b))
        myClass.myMethod<B> { Single.just(Response.success(b)) }.test().assertResult(b)
    }

    @Test
    fun tmp2() {
        every { myClass.myMethod(any<() -> Single<Response<A>>>()) } returns (Single.just(a))
        myClass.myMethod<A> { Single.just(Response.success(a)) }.test().assertResult(a)

        every { myClass.myMethod(any<() -> Single<Response<B>>>()) } returns (Single.just(b))
        myClass.myMethod<B> { Single.just(Response.success(b)) }.test().assertResult(b)
    }

    @Test
    fun tmp3() {
        every { myClass.myMethod(any<() -> Single<Response<A>>>()).hint(A::class) } returns (Single.just(a))
        myClass.myMethod<A> { Single.just(Response.success(a)) }.test().assertResult(a)

        every { myClass.myMethod(any<() -> Single<Response<B>>>()).hint(B::class) } returns (Single.just(b))
        myClass.myMethod<B> { Single.just(Response.success(b)) }.test().assertResult(b)
    }

    @Test
    fun tmp4() {
        every { myClass.myMethod<A>(any()).hint(A::class) } returns (Single.just(a))
        myClass.myMethod<A> { Single.just(Response.success(a)) }.test().assertResult(a)

        every { myClass.myMethod<B>(any()).hint(B::class) } returns (Single.just(b))
        myClass.myMethod<B> { Single.just(Response.success(b)) }.test().assertResult(b)
    }
}
Related