Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to go about unit testing onEach events in Viewmodel #644

Open
ssiddh opened this issue Aug 3, 2022 · 1 comment
Open

How to go about unit testing onEach events in Viewmodel #644

ssiddh opened this issue Aug 3, 2022 · 1 comment

Comments

@ssiddh
Copy link

ssiddh commented Aug 3, 2022

I am trying to unit test certain flows on the viewmodel which are triggered onEach subscription of the a specific property. https://airbnb.io/mavericks/#/core-concepts?id=subscribing-to-state-changes

I can correctly verify the state transitions in the unit test, but I am not able to verify functions called in response to onEach subscription. I looked through the documentation and could not find something that could help. Is there a way to achieve this?

example:

class SomeViewModel(initialState: SomeState, tracker: Tracker): MavericksViewModel<SomeState>(initialState) {
   init {
       onEach(SomeState::propertyA) {
           tracker.fireAnalyticsEvent() // Want to verify this function gets called on state changes 
       }
   }
}

class SomeViewModelTest {
    @get:Rule
    val mvrxTestRule = MvRxTestRule(testDispatcher = UnconfinedTestDispatcher())

    @Test
    fun sampleTest() {
        // given
        sut = SomeViewModel(SomeState(a, b, c), MockTracker())

        // when
        sut.doSomething()

        // then
        withState(sut) { state ->
             assertTrue(state.propertyA == a1) // This works
        }
        verify(1) {
            // Verify this function was called once
            tracker.fireAnalyticsEvent() // This fails
        }
    }
}

PS: Thank you for this amazing library, it is a delight to use.

@PayamGerackoohi
Copy link

Hi, sorry for the late answer, but if anyone is interested, verify(1) is wrong, because you're setting propertyA twice. First when you set the initial state, then when you call doSomething. The rest works fine for me:

import com.airbnb.mvrx.MavericksState
import com.airbnb.mvrx.MavericksViewModel
import com.airbnb.mvrx.test.MavericksTestRule
import com.airbnb.mvrx.withState
import io.mockk.confirmVerified
import io.mockk.justRun
import io.mockk.mockk
import io.mockk.verify
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import org.junit.Assert.assertTrue
import org.junit.Rule
import org.junit.Test

data class SomeState(val propertyA: String, val propertyB: String, val propertyC: String) : MavericksState

interface Tracker {
    fun fireAnalyticsEvent()
}

class SomeViewModel(initialState: SomeState, tracker: Tracker) : MavericksViewModel<SomeState>(initialState) {
    init {
        onEach(SomeState::propertyA) {
            println("*** propertyA: $it")
            tracker.fireAnalyticsEvent()
        }
    }

    fun doSomething() = setState { copy(propertyA = "a1") }
}

@OptIn(ExperimentalCoroutinesApi::class)
class SomeViewModelTest {
    @get:Rule
    val mavericksTestRule = MavericksTestRule(testDispatcher = UnconfinedTestDispatcher())

    @Test
    fun sampleTest() {
        // given
        val tracker = mockk<Tracker> { justRun { fireAnalyticsEvent() } }
        val sut = SomeViewModel(SomeState("a", "b", "c"), tracker)

        // when
        sut.doSomething()

        // then
        withState(sut) { state -> assertTrue(state.propertyA == "a1") }
        verify(exactly = 2) { tracker.fireAnalyticsEvent() }

        confirmVerified(tracker)
    }
}

This prints:

*** propertyA: a
*** propertyA: a1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants