web-dev-qa-db-ja.com

Kotlin Coroutine Unit ViewModelscopeによるテストフローコレクション

フローを収集する私のViewModelのメソッドをテストしたいです。コレクターの内側では、LiveDataオブジェクトが変わっています。これは最後にチェックしたいです。これはおおよそ設定の外観です。

_//Outside viewmodel
val f = flow { emit("Test") }.flowOn(Dispatchers.IO)

//Inside viewmodel
val liveData = MutableLiveData<String>()

fun action() {
    viewModelScope.launch { privateAction() }
}

suspend fun privateAction() {
    f.collect {
        liveData.value = it
    }
}
_

My Unit Testでaction()メソッドを呼び出すと、フローが収集される前にテストが終了します。これがテストの外観の外観です。

_@Test
fun example() = runBlockingTest {
    viewModel.action()
    assertEquals(viewModel.liveData.value, "Test")
}
_

このJUNIT5拡張子を介してTestCoroutIneSpatcherを使用しています。また、LiveDataのInstant Executor拡張機能も使用しています。

_    class TestCoroutineDispatcherExtension : BeforeEachCallback, AfterEachCallback, ParameterResolver {
    @SuppressLint("NewApi") // Only used in unit tests
    override fun supportsParameter(parameterContext: ParameterContext?, extensionContext: ExtensionContext?): Boolean {
        return parameterContext?.parameter?.type === testDispatcher.javaClass
    }

    override fun resolveParameter(parameterContext: ParameterContext?, extensionContext: ExtensionContext?): Any {
        return testDispatcher
    }

    private val testDispatcher = TestCoroutineDispatcher()

    override fun beforeEach(context: ExtensionContext?) {
        Dispatchers.setMain(testDispatcher)
    }

    override fun afterEach(context: ExtensionContext?) {
        Dispatchers.resetMain()
        testDispatcher.cleanupTestCoroutines()
    }
}

    class InstantExecutorExtension : BeforeEachCallback, AfterEachCallback {
    override fun beforeEach(context: ExtensionContext?) {
        ArchTaskExecutor.getInstance()
            .setDelegate(object : TaskExecutor() {
                override fun executeOnDiskIO(runnable: Runnable) = runnable.run()
                override fun postToMainThread(runnable: Runnable) = runnable.run()
                override fun isMainThread(): Boolean = true
            })
    }

    override fun afterEach(context: ExtensionContext?) {
        ArchTaskExecutor.getInstance().setDelegate(null)
    }
}
_
9
sunilson

それで私が終わったことは、ディスパッチャーをViewModelコンストラクタに渡すだけです。

_class MyViewModel(..., private val dispatcher = Dispatchers.Main)
_

そして次のように使ってください:

_viewModelScope.launch(dispatcher) {}
_

だから私はViewModelを使用してTestCoroutineDispatcherをインスタンス化してから、_testCoroutineDispatcher.runBlockingTest {}_などを使用して、これをオーバーライドできます。

0
sunilson