Boh*_*sen 3 android unit-testing kotlin kotlinx.coroutines
我最近开始在我的 Android 项目中使用 kotlin 协程,但我遇到了一些问题。许多人将其称为代码异味。
我正在使用 MVP 架构,其中协程在我的演示者中启动,如下所示:
// WorklistPresenter.kt
...
override fun loadWorklist() {
...
launchAsync { mViewModel.getWorklist() }
...
Run Code Online (Sandbox Code Playgroud)
该launchAsync函数以这种方式实现(在我的 WorklistPresenter 类扩展的 BasePresenter 类中):
@Synchronized
protected fun launchAsync(block: suspend CoroutineScope.() -> Unit): Job {
return launch(UI) { block() }
}
Run Code Online (Sandbox Code Playgroud)
问题在于我使用的是依赖于 Android 框架的 UI 协程上下文。我无法将其更改为另一个协程上下文而不会遇到ViewRootImpl$CalledFromWrongThreadException. 为了能够对此进行单元测试,我创建了一个 BasePresenter 的副本,其中包含不同的实现launchAsync:
protected fun launchAsync(block: suspend CoroutineScope.() -> Unit): Job {
runBlocking { block() }
return mock<Job>()
}
Run Code Online (Sandbox Code Playgroud)
对我来说这是一个问题,因为现在我的 BasePresenter 必须在两个地方维护。所以我的问题是。如何更改我的实现以支持简单的测试?
我最近了解了 Kotlin 协程,教我的人向我展示了解决这个问题的好方法。
您创建一个提供上下文的接口,具有默认实现:
interface CoroutineContextProvider {
val main: CoroutineContext
get() = Dispatchers.Main
val io: CoroutineContext
get() = Dispatchers.IO
class Default : CoroutineContextProvider
}
Run Code Online (Sandbox Code Playgroud)
并且您将 this ( CoroutineContextProvider.Default()) 注入到演示者构造函数中,无论是手动还是使用注入框架。然后在你的代码中使用它提供的上下文:provider.main; provider.io; 或任何你想定义的。现在,您可以愉快地使用launch,并withContext使用从您的提供商对象这些情况下,知道它会在你的应用程序正常运行,但您可以在测试过程中提供不同的上下文。
从您的测试中注入此提供程序的不同实现,其中所有上下文都在 Dispatchers.Unconfined
class TestingCoroutineContextProvider : CoroutineContextProvider {
@ExperimentalCoroutinesApi
override val main: CoroutineContext
get() = Dispatchers.Unconfined
@ExperimentalCoroutinesApi
override val io: CoroutineContext
get() = Dispatchers.Unconfined
}
Run Code Online (Sandbox Code Playgroud)
当你模拟挂起函数时,调用它包裹着runBlocking,这将确保所有操作都发生在调用线程(你的测试)中。它在此处进行了解释(请参阅有关“无限制与受限制的调度程序”的部分)。
| 归档时间: |
|
| 查看次数: |
2394 次 |
| 最近记录: |