JUnit 5 测试 - 无法观察嵌套的 LiveData 值

亚当·赫维茨

概述

预期- 在本地单元测试中保存嵌套的 LiveData 值,然后断言它们的值。

观察到- 在生产代码中成功观察到在 ViewModel 中保存嵌套的 LiveData 值,但在本地单元测试中失败。这可能是由于与在 Android 环境中运行相比,本地单元测试中缺少线程。

代码

  • 视图模型包含LOADINGCONTENTERROR用于当用户选择的内容以打开(LCE)的条件。
  • NotifyItemChangedEffect保存LiveData状态以更新视图。
  • NotifyItemChangedEffect保存在函数内部以保存发送到视图的内容。只有在这种CONTENT情况下,所选项目才会发送到保存了 LiveData 对象的视图ContentToPlay
  • 在生产中,该作品的观点的UI更新过程中LOADINGCONTENTERROR,虽然ContentToPlay只有在成功的返回CONTENT状态。

内容视图模型.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不返回LOADINGERROR条件。
  • 问题- 的嵌套 LiveData 值NotifyItemChangedEffect未保存在单元测试中,这会更新每个 LCE 条件中的视图。此代码在为 保存的 LiveData 内执行ContentToPlay此模式已记录并在生产中工作。

播放内容测试.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(...))
                }
            }
        }
    }
亚当·赫维茨

在所有 (LCE) 加载、内容、错误条件中保存 LiveData

保存ContentToPlayLiveData 值或null在 ViewModel 的所有 LCE 条件中,以确保同步返回值以进行本地单元测试。

注意- 此策略的缺点是它ContentToPlay向生产代码中的视图发出不必要值,这并不理想,但似乎不是主要问题。

内容视图模型.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))
                }
            }
        }
    })

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章