Hi All, we’ve been using Uniflow-kt for an android...
# uniflow
j
Hi All, we’ve been using Uniflow-kt for an android app at a fintech company in Mexico for the last year and it’s been great so far. We’re updating from
0.11.6
to
1.0.10
and ran into an issue and wanted to reach out to the community to see what you all recommend. Below is how we’ve been testing the default state of our viewmodels and we’ve never had issues.
Copy code
class FeatureFlagViewModel(
    private val featureFlagStorage: FeatureFlagStorage
) : AndroidDataFlow(defaultState = FeatureFlagScreenState(isButtonVisible = featureFlagStorage.getFeatureFlagState()!!)) {...}
Copy code
class FeatureFlagViewModelTest : BaseCovaltoUnitTest() {
    private val mockFeatureFlagStorage: FeatureFlagStorage = mockk(relaxed = true)
    private lateinit var viewModel: FeatureFlagViewModel
    private lateinit var view: TestViewObserver

    @Before
    fun setup() {
        coEvery {
            mockFeatureFlagStorage.getFeatureFlagState()
        } returns true

        viewModel = FeatureFlagViewModel(mockFeatureFlagStorage)
        view = viewModel.createTestObserver()
    }

    @Test
    fun `Should set feature flag states properly by default`() {
        assertThat(view.lastStateOrNull)
            .isEqualTo(
                FeatureFlagScreenState(isCreateAccountButtonVisible = true)
            )
    }
When I run the tests after upgrading to the stable version it fails with the error in the photo below. The issue seems to be that the viewmodel is initialized before it can be observed so we never see the default state set. In other tests when we call
viewModel.doStuff()
the viewmodel state is properly updated. An easy fix is to create the default state in the init method of the viewModel like this:
Copy code
class FeatureFlagViewModel(
    private val featureFlagStorage: FeatureFlagStorage
) : AndroidDataFlow() {

    init {
        action {
            setState(FeatureFlagScreenState(isCreateAccountButtonVisible = featureFlagStorage.getFeatureFlagState()!!))
        }
    }
However, this feels a bit cumbersome to do in every viewmodel we have. It would be great to keep instantiating state the way we’re currently doing it. What do you guys recommend we do though?
e
Basically your question boils down to: How do I unit test that an `AndroidDataFlow`'s initial state is observed as the first value by the observers? IDK the answer from the top of my head, but you could argue the following. You may trust a library like uniflow to be tested, and therefore that it will first set the initial state for your observers to receive. The thing to test might not be your
AndroidDataFlow
, but the factory that instantiates your data flow and the factory that instantiates the initial state.
👍 1
j
I think that’s a fair point because in the example we’re essentially testing the constructor for our
ViewModel
which is unnecessary. That said there are other places where we use
verifySequence()
in order to verify all changes to state and being able to do something like this feels reasonable.
Copy code
tester.verifySequence(
        MyState(value=0),
        MyState(value=1),
        MyState(value=2)
    )
Having to convert our tests to the below is fine, but I feel like being able to observe a
AndroidDataFlow
’s feels like something that should be doable…Especially because we were already able to do it 😅
Copy code
tester.verifySequence(
        MyState(value=1),
        MyState(value=2)
    )
e
I'm not saying it's impossible with UniFlow 1.0.10, but at this time I can't check how to actually do it. Maybe you can observe the data flow's data publisher?
j
That’s a good idea. I’ll take a look at that and see what I find. In the mean time we removed the majority of default state tests and used the
init {}
approach for any situations that truly needed to have their default state tested. Thanks for the help 🙂
a
Got it 👌