#android #kotlin #android-viewmodel #kotlin-coroutines
Вопрос:
У меня есть SharedFlow
. Когда ViewModel
он будет создан, я изменю значение на Val1
. После этого я использую viewModelScope
, чтобы сделать некоторую поддельную задержку 3 seconds
, а затем изменить значение на Val2
.
class MyViewModel : ViewModel() {
val x = MutableSharedFlow<String>()
init {
x.tryEmit("Val1")
viewModelScope.launch {
delay(3000)
x.tryEmit("Val2")
}
}
}
Вопрос
- Как мне проверить начальное значение
Val1
? - Как проверить, изменилось ли значение
Val2
после задержки?
Комментарии:
1. Если у вас нет буфера воспроизведения, никто никогда не сможет получить это начальное значение, потому что оно будет выдано и потеряно до того, как у подписчиков появится возможность начать сбор общего потока
Ответ №1:
Чтобы протестировать его, вам нужен способ ввести свой контекст тестирования. Обычно это делается путем установки его в качестве Dispatchers.Main.
Тогда самый простой путь — использовать MutableStateFlow
вместо MutableSharedFlow
. Вот пример:
class MyViewModel : ViewModel() {
val x = MutableStateFlow("Val1")
init {
viewModelScope.launch {
delay(3000)
x.tryEmit("Val2")
}
}
}
class MyViewModelTests {
private val testDispatcher = TestCoroutineDispatcher()
@Before
fun setUp() {
Dispatchers.setMain(testDispatcher)
}
@Test
fun test() = runBlocking {
// given
val myViewModel = MyViewModel()
// then
assertEquals("Val1", myViewModel.x.value)
// when
testDispatcher.advanceTimeBy(3000)
// then
assertEquals("Val2", myViewModel.x.value)
}
}
Если вы хотите протестировать MutableSharedFlow
, вам лучше перенести свою логику из конструктора в какую-нибудь функцию, например onCreate
. Затем вы должны собрать и понаблюдать, как меняются ваши ценности. Вот пример (мы могли бы сделать лучший с помощью некоторой библиотеки тестирования, такой как Turbine):
class MyViewModel : ViewModel() {
val x = MutableSharedFlow<String>()
fun onCreate() {
viewModelScope.launch {
x.emit("Val1")
delay(3000)
x.emit("Val2")
}
}
}
class MyViewModelTests {
private val testDispatcher = TestCoroutineDispatcher()
@Before
fun setUp() {
Dispatchers.setMain(testDispatcher)
}
@Test
fun test() = runBlocking {
// given
val myViewModel = MyViewModel()
var xChangeHistory = mapOf<Long, String>()
myViewModel.viewModelScope.launch {
myViewModel.x.collect {
xChangeHistory = testDispatcher.currentTime to it
}
}
// then
myViewModel.onCreate()
testDispatcher.advanceUntilIdle()
// then
assertEquals(mapOf(0L to "Val1", 3000L to "Val2"), xChangeHistory)
}
}
Комментарии:
1. Я знаю, как проверить поток состояний. Вопрос в том, как мне это сделать
SharedFlow
?2. Разве вторая часть не дает вам ответа? Если вы хотите сохранить эту функцию в качестве конструктора, установите
replay
для параметраSharedFlow
значение 1, и тогда будет возможно тестирование.3. Я прошу прощения. Я не смогу перенести свою логику из
init
блока в метод.