Описание проблемы:
Я ожидал, что значение LiveData будет MyState$Success при запуске теста, но для этого значения уже установлено нулевое значение.
Вопросы:
/>Выдает ли LiveData свое значение асинхронно и вызывает это несоответствие?
Должен ли я использовать другую стратегию тестирования для обработки обновлений LiveData в сопрограммах?
Как я могу гарантировать, что тест будет ждать до тех пор, пока окончательное состояние (MyState.Success) генерируется?
Будем признательны за любые идеи и предложения!
Ожидается: com.br.testesunitarios.ui.MyState$Success@62fad19
Фактическое: null
Вот моя реализация ViewModel
package com.br.testesunitarios.ui.home
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.br.testesunitarios.ui.MyState
import com.br.testesunitarios.ui.ProviderUseCase
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
class HomeViewModel : ViewModel() {
private val _state: MutableLiveData = MutableLiveData()
val state: LiveData = _state
fun interactor(interactor: String) {
when (interactor) {
"AnyInteractor" -> {
executarMetodo()
}
}
}
private fun executarMetodo() {
viewModelScope.launch {
try {
_state.value = MyState.Loading
delay(1000)
_state.value = MyState.Success
delay(1000)
when (ProviderUseCase().execute()) {
MyState.Success -> {
_state.value = MyState.Success
}
else -> {
_state.value = MyState.Failure
}
}
} catch (e: Exception) {
_state.value = MyState.Failure
}
}
}
}
Это мой тестовый пример с использованием StandardTestDispatcher и runTest:
package com.br.testesunitarios.ui.home
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.br.testesunitarios.ui.MyState
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.setMain
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.Assertions.assertEquals
import org.mockito.junit.MockitoJUnitRunner
import org.junit.runner.RunWith
@ExperimentalCoroutinesApi
@RunWith(MockitoJUnitRunner::class)
class HomeViewModelTest {
val instantExecutorRule = InstantTaskExecutorRule()
private val testDispatcher = StandardTestDispatcher()
@BeforeEach
fun setUp() {
Dispatchers.setMain(testDispatcher)
}
@AfterEach
fun tearDown() {
Dispatchers.resetMain()
}
@Test
fun `should execute executarMetodo when interactor is AnyInteractor`() = runTest {
val viewModel = HomeViewModel()
viewModel.interactor("AnyInteractor")
assertEquals(MyState.Success, viewModel.state.value) // This line fails
}
}
Настройка Gradle:
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.android)
}
android {
namespace = "com.br.testesunitarios"
compileSdk = 35
defaultConfig {
applicationId = "com.br.testesunitarios"
minSdk = 24
targetSdk = 35
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
buildFeatures {
viewBinding = true
}
}
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
implementation(libs.androidx.constraintlayout)
implementation(libs.androidx.lifecycle.livedata.ktx)
implementation(libs.androidx.lifecycle.viewmodel.ktx)
implementation(libs.androidx.navigation.fragment.ktx)
implementation(libs.androidx.navigation.ui.ktx)
testImplementation(libs.junit.jupiter)
testImplementation(libs.mockito.core)
testImplementation(libs.mockito.kotlin)
testImplementation(libs.mockito.jupiter)
testImplementation(libs.coroutines.test)
testImplementation(libs.arc.core.testing)
testImplementation (libs.junit.jupiter.api)
testRuntimeOnly(libs.junit.jupiter.engine)
testImplementation(libs.io.mockk)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
}
tasks.withType {
useJUnitPlatform()
}
И версии Lib
[versions]
agp = "8.6.1"
kotlin = "1.9.0"
coreKtx = "1.15.0"
junitVersion = "1.2.1"
espressoCore = "3.6.1"
appcompat = "1.7.0"
material = "1.12.0"
constraintlayout = "2.2.0"
lifecycleLivedataKtx = "2.8.7"
lifecycleViewmodelKtx = "2.8.7"
navigationFragmentKtx = "2.8.5"
navigationUiKtx = "2.8.5"
junitJupiter = "5.11.3"
mockitoCore = "5.7.0"
mockitoKotlin = "5.2.0"
mockitoJupiter = "5.7.0"
coroutinesTest = "1.7.3"
arcCoreTesting = "2.2.0"
ioMockk = "1.13.5"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
junit-jupiter-api = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junitJupiter" }
junit-jupiter-engine = { group = "org.junit.jupiter", name = "junit-jupiter-engine", version.ref = "junitJupiter" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "lifecycleLivedataKtx" }
androidx-lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycleViewmodelKtx" }
androidx-navigation-fragment-ktx = { group = "androidx.navigation", name = "navigation-fragment-ktx", version.ref = "navigationFragmentKtx" }
androidx-navigation-ui-ktx = { group = "androidx.navigation", name = "navigation-ui-ktx", version.ref = "navigationUiKtx" }
junit-jupiter = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junitJupiter" }
mockito-core = { group = "org.mockito", name = "mockito-core", version.ref = "mockitoCore" }
mockito-kotlin = { group = "org.mockito.kotlin", name = "mockito-kotlin", version.ref = "mockitoKotlin" }
mockito-jupiter = { group = "org.mockito", name = "mockito-junit-jupiter", version.ref = "mockitoJupiter" }
coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "coroutinesTest" }
arc-core-testing = { group = "androidx.arch.core", name = "core-testing", version.ref = "arcCoreTesting" }
io-mockk = { group = "io.mockk", name = "mockk", version.ref = "ioMockk" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin"
}
Подробнее здесь: https://stackoverflow.com/questions/792 ... el-test-wi
Тест LiveData не пройден: ожидался MyState $Success, но в тесте ViewModel с сопрограммами получено значение null ⇐ Android
Форум для тех, кто программирует под Android
1734099843
Anonymous
Описание проблемы:
Я ожидал, что значение LiveData будет MyState$Success при запуске теста, но для этого значения уже установлено нулевое значение.
Вопросы:
/>Выдает ли LiveData свое значение асинхронно и вызывает это несоответствие?
Должен ли я использовать другую стратегию тестирования для обработки обновлений LiveData в сопрограммах?
Как я могу гарантировать, что тест будет ждать до тех пор, пока окончательное состояние (MyState.Success) генерируется?
Будем признательны за любые идеи и предложения!
Ожидается: com.br.testesunitarios.ui.MyState$Success@62fad19
Фактическое: null
Вот моя реализация ViewModel
package com.br.testesunitarios.ui.home
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.br.testesunitarios.ui.MyState
import com.br.testesunitarios.ui.ProviderUseCase
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
class HomeViewModel : ViewModel() {
private val _state: MutableLiveData = MutableLiveData()
val state: LiveData = _state
fun interactor(interactor: String) {
when (interactor) {
"AnyInteractor" -> {
executarMetodo()
}
}
}
private fun executarMetodo() {
viewModelScope.launch {
try {
_state.value = MyState.Loading
delay(1000)
_state.value = MyState.Success
delay(1000)
when (ProviderUseCase().execute()) {
MyState.Success -> {
_state.value = MyState.Success
}
else -> {
_state.value = MyState.Failure
}
}
} catch (e: Exception) {
_state.value = MyState.Failure
}
}
}
}
Это мой тестовый пример с использованием StandardTestDispatcher и runTest:
package com.br.testesunitarios.ui.home
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.br.testesunitarios.ui.MyState
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.setMain
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.Assertions.assertEquals
import org.mockito.junit.MockitoJUnitRunner
import org.junit.runner.RunWith
@ExperimentalCoroutinesApi
@RunWith(MockitoJUnitRunner::class)
class HomeViewModelTest {
val instantExecutorRule = InstantTaskExecutorRule()
private val testDispatcher = StandardTestDispatcher()
@BeforeEach
fun setUp() {
Dispatchers.setMain(testDispatcher)
}
@AfterEach
fun tearDown() {
Dispatchers.resetMain()
}
@Test
fun `should execute executarMetodo when interactor is AnyInteractor`() = runTest {
val viewModel = HomeViewModel()
viewModel.interactor("AnyInteractor")
assertEquals(MyState.Success, viewModel.state.value) // This line fails
}
}
Настройка Gradle:
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.android)
}
android {
namespace = "com.br.testesunitarios"
compileSdk = 35
defaultConfig {
applicationId = "com.br.testesunitarios"
minSdk = 24
targetSdk = 35
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
buildFeatures {
viewBinding = true
}
}
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
implementation(libs.androidx.constraintlayout)
implementation(libs.androidx.lifecycle.livedata.ktx)
implementation(libs.androidx.lifecycle.viewmodel.ktx)
implementation(libs.androidx.navigation.fragment.ktx)
implementation(libs.androidx.navigation.ui.ktx)
testImplementation(libs.junit.jupiter)
testImplementation(libs.mockito.core)
testImplementation(libs.mockito.kotlin)
testImplementation(libs.mockito.jupiter)
testImplementation(libs.coroutines.test)
testImplementation(libs.arc.core.testing)
testImplementation (libs.junit.jupiter.api)
testRuntimeOnly(libs.junit.jupiter.engine)
testImplementation(libs.io.mockk)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
}
tasks.withType {
useJUnitPlatform()
}
И версии Lib
[versions]
agp = "8.6.1"
kotlin = "1.9.0"
coreKtx = "1.15.0"
junitVersion = "1.2.1"
espressoCore = "3.6.1"
appcompat = "1.7.0"
material = "1.12.0"
constraintlayout = "2.2.0"
lifecycleLivedataKtx = "2.8.7"
lifecycleViewmodelKtx = "2.8.7"
navigationFragmentKtx = "2.8.5"
navigationUiKtx = "2.8.5"
junitJupiter = "5.11.3"
mockitoCore = "5.7.0"
mockitoKotlin = "5.2.0"
mockitoJupiter = "5.7.0"
coroutinesTest = "1.7.3"
arcCoreTesting = "2.2.0"
ioMockk = "1.13.5"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
junit-jupiter-api = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junitJupiter" }
junit-jupiter-engine = { group = "org.junit.jupiter", name = "junit-jupiter-engine", version.ref = "junitJupiter" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "lifecycleLivedataKtx" }
androidx-lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycleViewmodelKtx" }
androidx-navigation-fragment-ktx = { group = "androidx.navigation", name = "navigation-fragment-ktx", version.ref = "navigationFragmentKtx" }
androidx-navigation-ui-ktx = { group = "androidx.navigation", name = "navigation-ui-ktx", version.ref = "navigationUiKtx" }
junit-jupiter = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junitJupiter" }
mockito-core = { group = "org.mockito", name = "mockito-core", version.ref = "mockitoCore" }
mockito-kotlin = { group = "org.mockito.kotlin", name = "mockito-kotlin", version.ref = "mockitoKotlin" }
mockito-jupiter = { group = "org.mockito", name = "mockito-junit-jupiter", version.ref = "mockitoJupiter" }
coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "coroutinesTest" }
arc-core-testing = { group = "androidx.arch.core", name = "core-testing", version.ref = "arcCoreTesting" }
io-mockk = { group = "io.mockk", name = "mockk", version.ref = "ioMockk" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin"
}
Подробнее здесь: [url]https://stackoverflow.com/questions/79278635/livedata-test-fails-expected-mystatesuccess-but-got-null-in-viewmodel-test-wi[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия