Hey guys, how are you? I'm trying to replace LiveD...
# android
o
Hey guys, how are you? I'm trying to replace LiveData to use the new Kotlin's Flow features. I am experimenting a bit with States and Events (any link would be appreciated, but it has to contain some documentations about TESTING) Here is a dummy
ViewModel
for UI Events (i.e. show a snackbar or navigate to another screen)
Copy code
class MyViewModel(
    private val shouldGoToX: ShouldGoToXUseCase
) : ViewModel() {

    private val eventChannel = BroadcastChannel<MyEvent>(Channel.BUFFERED)
    val events = eventChannel.asFlow()

    fun onCreate() = viewModelScope.launch {
        delay(3_000L)
        val navigationEvent = if (shouldGoToX()) {
            MyEvent.NavigateToX
        } else {
            MyEvent.NavigateToY
        }
        eventChannel.offer(navigationEvent)
    }

}

internal sealed class MyEvent {
    object NavigateToX : MyEvent()
    object NavigateToY : MyEvent()
}
And here is my test class
Copy code
internal class MyViewModelTest {

    @get:Rule
    val testInstantTaskExecutorRule = InstantTaskExecutorRule()

    @get:Rule
    val testCoroutineRule = TestCoroutineRule()

    private val shouldGoToX = mockk<ShouldGoToXUseCase>()
    private val viewModel = MyViewModel(shouldGoToX)

    @Test
    fun `GIVEN the user should go to X WHEN starting the screen THEN the user should see the X Screen`() =
        testCoroutineRule.runBlockingTest {
            //GIVEN
            coEvery { shouldGoToX() } returns false

            //WHEN
            viewModel.onCreate()

            val events = viewModel.events.toList()

            //THEN
            assertEquals(MyEvent.NavigateToX, events.first())
        }
}
Few questions: 1. Any observations about the approach (events sent through a
BroadcastChannel
? 2. I'm currently getting this error in the tests, but I've correctly set the test coroutines stuff
java.lang.IllegalStateException: This job has not completed yet
. Am I doing something wrong there?
c
I use a very similar pattern, but use a normal
Channel(capacity = Channel.BUFFERED)
instead of
BroadcastChannel
. Given that they are one-time events, having multiple subscribers could cause the snackbar to show multiple times, or navigation to be attempted multiple times, and a normal Channel will help ensure that doesn’t happen. I’ve also never had great luck with
runBlockingTest
, and usually just use normal
runBlocking
in my unit tests instead.
o
Noice! Good to know. Do you have a sample repo?
c
Unfortunately, no, this is a private repo
o
😢 Any chance you can find 5 minutes to create a small, sample project? 🙏
c
There’s not much more to it than what you’ve already got in the snippet you posted. Just try replacing
BroadcastChannel<MyEvent>(Channel.BUFFERED)
with
Channel(capacity = Channel.BUFFERED)
, and
runBlockingTest
with
runBlocking
o
Yeah, I've done it, no luck XD