Getting error MockKException: no answer found for: Observer(#8).onChanged Android

8.9k views Asked by At

I'm writing a unit test. Below is my code. The architecture is MVVM using Dagger2. I'm calling the login function residing in the LoginViewModel, which is notifying the getLoginState function. The error I'm getting is:

Error:

 io.mockk.MockKException: no answer found for: Observer(#8).onChanged(Success(data=))
    
        at io.mockk.impl.stub.MockKStub.defaultAnswer(MockKStub.kt:90)

LoginViewModelClass:

 fun logIn(phone: String, phoneCode: String) {
        loginState.value = Outcome.success("")
}

 fun getLoginState(): LiveData<Outcome<String>> = loginState
 

LoginViewModelTest class:

 @RelaxedMockK
    var SUT: LoginViewModel? = null

    @Mock
    var loginInteractor: LoginInteractor? = null

    @Mock
    var textValidator: TextValidator? = null

    @Mock
    var textProvider: TextProvider? = null

    @Mock
    var blinkUserPreferences: BlinkUserPreferences? = null

    @get:Rule
    var rule: TestRule = InstantTaskExecutorRule()

    @RelaxedMockK
    var mockObserver: Observer<Outcome<String>>? = null
    @Before
        fun setUp() {
    
            MockKAnnotations.init(this, relaxUnitFun = true)
             SUT = spyk(
                 LoginViewModel(
                         mockk<LoginInteractor>(),
                         mockk<TextValidator>(relaxed = true),
                         mockk<TextProvider>(),
                         mockk<BlinkUserPreferences>()))
            mockObserver = mockk<Observer<Outcome<String>>>()
             SUT!!.getLoginState().observeForever(mockObserver!!)
    
        }
     @Test
        fun logIn() {
            //Arrange 
            every {SUT!!.getLoginState().value} returns Outcome.success("")
    
            //Act 
            SUT!!.logIn("89989676","89998")

        //Assert  
        verify() { mockObserver!!.onChanged(Outcome.success("abc")) } 
    }

Question: In verification, why onChanged method is not being called, or what does it mean that no answer found for Observer().onChanged, how can I notify my onChanged method so I can verify it?

1

There are 1 answers

0
Ahmad Shahwaiz On BEST ANSWER

After watching this: https://mockk.io/#answers. It says

specify that the matched call answers with a code block scoped with answer scope

I just posted this:

every { mockObserver!!.onChanged(any()) } answers {}

in the following test function and it worked.

@Test
 fun logIn() {
            //Arrange 
            every { mockObserver!!.onChanged(any()) } answers {}
            every {SUT!!.getLoginState().value} returns Outcome.success("abc")
    
            //Act 
            SUT!!.logIn("89989676","89998")

            //Assert  
            verify() { mockObserver!!.onChanged(Outcome.success("abc")) } 
    }

According to my understanding, if you mockk a function, and you want to use its particular function you must use the every expression to tell framework that it will answer, because framework needs to know that it needs to answer something.

And if you want that all behaviour functions should also be added with mock with their implementation then you must spyk your class so that it gets the behaviour as well and then you can easily use the function without using expression every.

Please note that every expression is used for many cases like to get a mocked result out of that function, or just need to tell the framework that this function should answers this.

Please correct me through comments if I'm wrong, Ill update it.