Kotlin coroutinesを用いたTestで、処理が思うような順番で実行されない時の対処法
はじめに
ViewModelでよくあるようなパターンの、suspend functionではなく内部でコルーチンを起動しているようなメソッドを書くときに詰まったのでメモ用に投稿します。
class SampleViewModel(
private val sampleApi: SampleApi
) : ViewModel() {
private val _sampleStateFlow = MutableStateFlow(false)
val sampleStateFlow: StateFlow<Boolean>()
get() = _sampleStateFlow
fun sample() {
viewModelScope.launch {
_sampleStateFlow.value = true
}
}
}
こういうメソッドではメソッドの内部でコルーチンを起動している関係上、sample()内部の処理が完全に終わった後にその後の処理が実行されるわけではないので
@Test
fun sample_test() {
viewModel.sample()
assertThat(viewModel.sampleStateFlow.value).isTrue() //assertionにgoogle/truthを使用
}
のように書くとテストが失敗する場合があります。今までは
@Test
fun sample_test() = runBlockingTest {
viewModel.sample()
assertThat(viewModel.sampleStateFlow.value).isTrue()
}
とすれば良かったのですが、runBlockingTestが非推奨になっているのでその代替策をまとめます。
runTestとUnconfinedTestDispatcher()を併用する
@Before
fun setUp() {
Dispatchers.setMain(UnconfinedTestDispatcher())
}
@After
fun after() {
Dispatchers.resetMain()
}
@Test
fun sample_test() = runTest() {
viewModel.sample()
assertThat(viewModel.sampleStateFlow.value).isTrue()
}
advanceUntilIdle()を用いる
@Test
fun sample_test() = runTest() {
viewModel.sample()
advanceUntilIdle() //testScopeの中で待機していたコルーチンの処理が終わるまで待ってくれる
assertThat(viewModel.sampleStateFlow.value).isTrue()
}
Job型で返して、テストメソッドでjoin()する
//SampleViewModel側
fun sample() = viewModelScope.launch {
_sampleStateFlow.value = true
}
@Test
fun sample_test() = runTest {
viewModel.sample().join()
assertThat(viewModel.sampleStateFlow.value).isTrue() //assertionにgoogle/truthを使用
}
終わりに
公式の文献をちゃんと読むことが大事だと再認識しました…。
参考文献
Author And Source
この問題について(Kotlin coroutinesを用いたTestで、処理が思うような順番で実行されない時の対処法), 我々は、より多くの情報をここで見つけました https://qiita.com/nemo-855/items/2d59d5bb4017bad63797著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .