Expected-将嵌套的LiveData值保存在本地单元测试中,然后声明它们的值。
Observed-在生产代码中成功观察到将嵌套LiveData值保存在ViewModel中,但是在本地单元测试中失败。这可能是由于本地单元测试与在Android环境上运行相比缺少线程。
LOADING
,CONTENT
和ERROR
(LCE)条件。NotifyItemChangedEffect
状态以更新视图。NotifyItemChangedEffect
保存在函数内部,以保存发送到视图的内容。 仅在CONTENT
条件下,所选项目被发送到保存有LiveData对象ContentToPlay
的视图。LOADING
,CONTENT
和ERROR
期间视图的UI更新,而在成功ContentToPlay
条件下返回[[only CONTENT
。 ContentViewModel.kt
is ContentSelected -> {
_feedViewState.value = _feedViewState.value?.copy(
// LiveData value for ContentToPlay initiated here.
contentToPlay = switchMap(getAudiocast(contentSelected)) { lce ->
liveData {
when (lce) {
is Loading ->
_viewEffect.value = _viewEffect.value?.copy(
notifyItemChanged = liveData {
emit(Event(NotifyItemChangedEffect(...)))
})
is Lce.Content -> {
_viewEffect.value = _viewEffect.value?.copy(
notifyItemChanged = liveData {
emit(Event(NotifyItemChangedEffect(...)))
})
// LiveData value for ContentToPlay saved here.
emit(Event(lce.packet))
}
is Error -> {
_viewEffect.value = _viewEffect.value?.copy(
notifyItemChanged = liveData {
emit(Event(NotifyItemChangedEffect(...)))
})
_viewEffect.value = _viewEffect.value?.copy(
snackBar = liveData {
emit(Event(SnackBarEffect(...)))
})
}
}
}
})
...
}
ContentToPlay
和LOADING
条件下不返回ERROR
。NotifyItemChangedEffect
的嵌套LiveData值未保存在单元测试中,该单元测试会在每个LCE条件下更新视图。该代码在为ContentToPlay
保存的LiveData内部执行。该模式已记录并在生产中工作。 PlayContentTests.kt
@ExtendWith(InstantExecutorExtension::class)
class PlayContentTests {
@ParameterizedTest
@MethodSource("FeedLoad")
fun `Play Content`(test: PlayContentTest) = runBlocking {
// ViewModel method included to initiate ContentSelected event.
...
when (test.lceState) {
LOADING ->
assertThat(contentViewModel.viewEffect.getOrAwaitValue().notifyItemChanged.getOrAwaitValue().peekEvent()).isEqualTo(
NotifyItemChangedEffect(...))
CONTENT -> {
assertThat(contentViewModel.feedViewState.getOrAwaitValue().contentToPlay.getOrAwaitValue().peekEvent()).isEqualTo(
ContentToPlay(...))
assertThat(contentViewModel.viewEffect.getOrAwaitValue().notifyItemChanged.getOrAwaitValue().peekEvent()).isEqualTo(
NotifyItemChangedEffect(...))
}
ERROR -> {
assertThat(contentViewModel.feedViewState.getOrAwaitValue().contentToPlay.getOrAwaitValue().peekEvent()).isEqualTo(
ContentToPlay(...))
assertThat(contentViewModel.viewEffect.getOrAwaitValue().notifyItemChanged.getOrAwaitValue().peekEvent()).isEqualTo(
NotifyItemChangedEffect(...))
}
}
}
}
ContentToPlay
LiveData值或null
,以确保为本地单元测试同步返回值。 Note-此策略的缺点是,它会在生产代码中不必要地向视图发出ContentToPlay
值,这不是理想的,但似乎不是主要问题。
ContentViewModel.kt
_feedViewState.value = _feedViewState.value?.copy(contentToPlay =
switchMap(getAudiocast(contentSelected)) { lce ->
liveData {
when (lce) {
is Loading -> {
setContentLoadingStatus(contentSelected.content.id, View.VISIBLE)
_viewEffect.value = _viewEffect.value?.copy(
notifyItemChanged = liveData {
emit(Event(NotifyItemChangedEffect(contentSelected.position)))
})
// Empty ContentToPlay saved.
emit(Event(null))
}
is Lce.Content -> {
setContentLoadingStatus(contentSelected.content.id, View.GONE)
_viewEffect.value = _viewEffect.value?.copy(
notifyItemChanged = liveData {
emit(Event(NotifyItemChangedEffect(contentSelected.position)))
})
// ContentToPlay saved.
emit(Event(lce.packet))
}
is Error -> {
setContentLoadingStatus(contentSelected.content.id, View.GONE)
_viewEffect.value = _viewEffect.value?.copy(
notifyItemChanged = liveData {
emit(Event(NotifyItemChangedEffect(contentSelected.position)))
})
if (lce.packet.filePath.equals(TTS_CHAR_LIMIT_ERROR))
_viewEffect.value = _viewEffect.value?.copy(
snackBar = liveData {
emit(Event(SnackBarEffect(TTS_CHAR_LIMIT_ERROR_MESSAGE)))
})
else _viewEffect.value = _viewEffect.value?.copy(
snackBar = liveData {
emit(Event(SnackBarEffect(CONTENT_PLAY_ERROR)))
})
// Empty ContentToPlay saved.
emit(Event(null))
}
}
}
})