Michael Friend
07/08/2020, 3:09 PM// The view model
class LazyViewModel(val repo: Repo) : ViewModel() {
val state: LiveData<State<String>> by lazy {
loadData()
_state
}
private val _state = MutableLiveData<State<String>>()
private fun loadData() {
viewModelScope.launch {
_state.value = State.Loading
_state.value = State.Data(repo.getData())
}
}
}
// the test
@Test
fun `get loading then data`() = coroutinesTestRule.testScope.runBlockingTest {
val mockObserver: Observer<State<String>> = mockk(relaxUnitFun = true)
val mockRepo: Repo = mockk {
coEvery { getData() } returns "data"
}
val viewModel = LazyViewModel(mockRepo)
// If I don't pause then resume the dispatcher _state.value = State.Loading seemingly gets skipped
pauseDispatcher()
viewModel.state.observeForever(mockObserver)
resumeDispatcher()
verifyOrder {
mockObserver.onChanged(State.Loading)
mockObserver.onChanged(State.Data("data"))
}
}
Mgj
07/08/2020, 3:13 PMMgj
07/08/2020, 3:24 PMopen class MyViewModel {
protected open val mScope = CoroutineScope(Dispatchers.Main)
}
and then in tests use:
class MyViewModelStub : MyViewModel {
override val mScope = TestCoroutineScope()
}
Michael Friend
07/08/2020, 3:29 PMMgj
07/08/2020, 3:29 PMopen class MyViewModel {
protected open val mScope = viewModelScope
}
Michael Friend
07/08/2020, 3:30 PMval state: LiveData<State<String>> = liveData {
// This HAS to be called first for the test to work
emitSource(_state)
loadData()
}
private val _state = MutableLiveData<State<String>>()
private fun loadData() {
viewModelScope.launch {
_state.value = State.Loading
_state.value = State.Data(repo.getData())
}
}