Skip to content

Instantly share code, notes, and snippets.

@Nunocky
Last active June 22, 2023 07:16
Show Gist options
  • Save Nunocky/3045f35e985e5d1476ea56114ef61ccc to your computer and use it in GitHub Desktop.
Save Nunocky/3045f35e985e5d1476ea56114ef61ccc to your computer and use it in GitHub Desktop.
Android ViewModellのテスト。 savedStateHandle で値の保存と復元が行われることを確かめる。
package com.example.myapplication
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
class MainViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {
var value1: Int
get() = savedStateHandle.get<Int>("value1") ?: 0
set(v) = savedStateHandle.set("value1", v)
private val _value2: MutableLiveData<Int> = savedStateHandle.getLiveData("value2", -1)
val value2 = _value2 as LiveData<Int>
fun setValue2(v: Int) {
viewModelScope.launch {
_value2.value = v
}
}
val value3 = savedStateHandle.getStateFlow("value3", -987).asLiveData()
fun setValue3(v: Int) {
viewModelScope.launch {
savedStateHandle["value3"] = v
}
}
}
package com.example.myapplication
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.lifecycle.LiveData
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.testing.TestLifecycleOwner
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.test.setMain
import kotlinx.coroutines.withContext
import org.junit.After
import org.junit.Assert.*
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
@ExperimentalCoroutinesApi
@RunWith(JUnit4::class)
class MainViewModelTest {
@get:Rule
val instantTaskExecutorRule = InstantTaskExecutorRule()
@Before
fun setUp() {
Dispatchers.setMain(Dispatchers.Unconfined)
}
@After
fun tearDown() {
Dispatchers.resetMain()
}
/**
* SavedStateHandleのテスト
*/
@Test
fun test1() = runTest {
val handle = SavedStateHandle()
val viewModel = MainViewModel(handle)
// -------------------------------------
// 初期値
// -------------------------------------
waitForLiveDataChange(-1, viewModel.value2)
waitForLiveDataChange(-987, viewModel.value3)
assertEquals(viewModel.value1, 0)
assertEquals(-1, viewModel.value2.value)
assertEquals(-987, viewModel.value3.value)
// -------------------------------------
// 値のセットが行われる
// -------------------------------------
viewModel.value1 = 2
viewModel.setValue2(-999)
viewModel.setValue3(1024)
waitForLiveDataChange(-999, viewModel.value2)
waitForLiveDataChange(1024, viewModel.value3)
assertEquals(2, viewModel.value1)
assertEquals(-999, viewModel.value2.value)
assertEquals(1024, viewModel.value3.value)
// -------------------------------------
// SavedStateHandleにより値が復元される
// -------------------------------------
val viewModel2 = MainViewModel(handle)
assertEquals(2, viewModel2.value1)
waitForLiveDataChange(-999, viewModel.value2)
waitForLiveDataChange(1024, viewModel.value3)
}
/**
* LiveDataの値が変更されるまで待つ
*/
private suspend fun <T> waitForLiveDataChange(
expected: T,
liveData: LiveData<T>,
timeout: Long = 3000
) {
val latch = CountDownLatch(1)
val observer = object: Observer<T> {
override fun onChanged(value: T) {
if (value == expected) {
latch.countDown()
liveData.removeObserver(this)
}
}
}
liveData.observeForever(observer)
withContext(Dispatchers.IO) {
latch.await(timeout, TimeUnit.MILLISECONDS)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment