I have a simple ViewModel with a state that keeps some data. State is initialized in the init function of my ViewModel:
ViewModelState.kt
data class ViewModelState(
val myInfo: String = "",
val mySecondInfo: String = ""
)
MyViewModel.kt
class MyViewModel(
private val client: Client
): ViewModel() {
private val _state = MutableStateFlow(ViewModelState())
val state = _state.asStateFlow()
init {
loadMyInfoFromClient()
loadMySecondInfoFromClient()
}
private fun loadMyInfoFromClient() {
viewModelScope.launch {
val retrievedData = client.suspendFunction()
_state.update {
it.copy(myInfo = retrievedData)
}
}
}
private fun loadMySecondInfoFromClient() {
// same thing as loadMyInfoFromClient()
}
}
When it comes to test that ViewModel using Turbine, what is the best practice to await for different states to be emitted and check the values? Today I use several chained awaitItem() but it seems ugly to me.
fun `test state initialization`() = runTest {
// Given
prepareMockForClient()
// When
val underTest = MyViewModel(mockedClient)
// Then
underTest.state.test {
val firstState = awaitItem()
assertThat(firstState.myInfo).isEqualTo("blabla")
val secondState = awaitItem()
assertThat(secondState.mySecondInfo).isEqualTo("bleble")
}
}
I didn't find a way to wait for the last emitted state in Turbine so that I could check the whole state with something like:
underTest.state.test {
val state = awaitLastItem()
assertThat(state.myInfo).isEqualTo("blabla")
assertThat(state.mySecondInfo).isEqualTo("bleble")
}
Except coding myself that awaitLastItem()
, is there a better practice in Android to test the initial state of your ViewModel?
Thank you!
if someone's looking for an answer. I ended up using ideas proposed in the following articles: here and here.
init{}
to a public method that I call in onCreated() method.advanceUntilIdle()
method to get the final state to check that the whole state has been correctly set after calling the public method initializing the state.Code is more robust and testing strategy is easier now. Hope it can help.