Тест JUnit 5 - невозможно определить вложенные значения LiveData - PullRequest
0 голосов
/ 11 октября 2019

Обзор

Ожидается - Сохранение вложенных значений LiveData в локальном модульном тесте с последующим подтверждением их значений.

Соблюдается - Сохранение вложенных значений LiveData в ViewModel успешно выполняется в рабочем коде, но не выполняется в локальном модульном тесте. Это может быть связано с отсутствием многопоточности в локальных модульных тестах по сравнению с работой в среде Android.

Код

  • ViewModel содержит LOADING, CONTENT и ERROR (LCE) условия, когда пользователь выбирает содержимое для открытия.
  • Состояние LiveData NotifyItemChangedEffect сохраняется для обновления представления.
  • NotifyItemChangedEffect сохраняется внутри функциисохранить контент, отправленный на просмотр. Только в условии CONTENT, выбранный элемент отправляется в представление с сохраненным объектом LiveData, ContentToPlay.
  • В работе это работает с обновлением пользовательского интерфейса представления во время LOADING, CONTENT и ERROR, в то время как ContentToPlay является только , возвращенными в успешном состоянии 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 условия.
  • выпуск - вложенные значения LiveData для NotifyItemChangedEffect не сохраняются в модульном тесте, который обновляет представление в каждом условии LCE. Этот код выполняется внутри LiveData, сохраненного для ContentToPlay. Этот шаблон зарегистрирован и работает в производстве.

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(...))
                }
            }
        }
    }

1 Ответ

0 голосов
/ 11 октября 2019

Сохранение LiveData во всех (LCE) условиях загрузки, содержимого, ошибок

Сохранение значения ContentToPlay LiveData или null во всех условиях LCE ViewModel для обеспечения синхронного возврата значения для локальной единицытестирование.

Примечание - Недостатком этой стратегии является то, что она излишне генерирует значение 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))
                }
            }
        }
    })
...