首页 > 解决方案 > 如何将其他调度程序注入 MainCoroutineRule?

问题描述

Google Codelab for Coroutines中,我们看到了一个MainCoroutineScopeRule. 在规则中,它解释了该规则可以扩展到其他调度程序,除了Dispatchers.Main

override fun starting(description: Description?) {
    super.starting(description)
    // If your codebase allows the injection of other dispatchers like
    // Dispatchers.Default and Dispatchers.IO, consider injecting all of them here
    // and renaming this class to `CoroutineScopeRule`
    //
    // All injected dispatchers in a test should point to a single instance of
    // TestCoroutineDispatcher.
    Dispatchers.setMain(dispatcher)
}

我的问题是,我们究竟如何注入其他调度程序?这是否假设我们正在使用依赖注入?如果是这样,如果我不使用 DI 怎么办,我还能将此规则扩展到其他调度程序吗?我在kotlinx-coroutines-test库中看不到任何允许我将 设置TestCoroutineDispatcher为其他调度程序的内容。所以,有这个:

Dispatchers.setMain(dispatcher)

...但不是这个:

Dispatchers.setIO(dispatcher) // Or Default, etc.

我是否希望重写我的suspend函数以接收调度程序作为参数:

suspend doSomeIO(dispatcher: CoroutineDispatcher = Dispatchers.IO) {
    launch(dispatcher) {
        // Some long-running IO operation
    }
}

标签: androidunit-testingkotlin-coroutines

解决方案


您是正确的,因为这确实假设您正在注入调度程序。如果您不使用主调度程序,则应该注入调度程序以正确测试它。

如果您想强制该特定函数位于 Dispatchers.IO 线程上,那么您编写挂起函数的方式是一种方法。但是,您最终将获得嵌套启动。

取而代之的是,我只需将调度程序传递给 viewModel,并让 viewmodel 决定如何调用挂起函数。

//Your version:
  
suspend fun doSomeIO(dispatcher: CoroutineDispatcher = Dispatchers.IO) {
    launch(dispatcher) {
        // Some long-running IO operation
    }
}

class MyViewModel(val dispatcher: CoroutineDispatcher = Dispatchers.IO: ViewModel() {

  init {
    viewModelScope.launch {
      doSomeIO(dispatcher) // here you are launching one coroutine inside the other
    }
  }
}

// Instead try this: 

suspend fun doSomeIO() {
        // Some long-running IO operation
}

class MyViewModel(val dispatcher: CoroutineDispatcher = Dispatchers.IO: ViewModel() {

  init {
    viewModelScope.launch(dispatcher) {
      doSomeIO()
    }
  }
}

推荐阅读