使用 Dispatchers.IO 进行 Kotlin 协程测试

Kotlin Coroutine Testing with Dispatchers.IO

所以也许有一个教程讨论了这个问题,但是 none 我读过的教程已经为我解决了这个问题。我的结构如下,我正在尝试进行单元测试,但是当我去测试时,我总是无法说明 repo 方法 doSomthing() 从未被调用过。我最好的猜测是因为我在不同的上下文中启动了一个新的协程。那我该如何测试呢?

存储库

interface Repository {
    suspend fun doSomething(): String
}

查看模型

class ViewModel(val repo: Repository) {
    val liveData = MutableLiveData<String>()
    fun doSomething {
    //Do something here
        viewModelScope.launch(Dispatchers.IO) {
            val data = repo.doSomething()
            withContext(Dispatchers.Main) {
                liveData.value = data
            }
        }
    }
}

查看模型测试

class ViewModelTest {
    lateinit var viewModel: ViewModel
    lateinit var repo: Repository

    @Before
    fun setup() {
        Dispatchers.setMain(TestCoroutineDispatcher())
        repo = mock<Repository>()
        viewModel = ViewModel(repo)
    }

    @Test
    fun doSomething() = runBlockingTest {
        viewModel.doSomething()
        viewModel.liveData.test().awaitValue().assertValue {
            // assert something
        }
        verify(repo).doSomthing()
    }
}

根据Google:

Dispatchers 应该注入到您的 ViewModels 中,以便您可以正确测试。您正在通过 Dispatchers.setMainTestCorotutineDispatcher 设置为主调度程序,它控制 MainDispatcher,但您仍然无法控制通过 viewModelScope.launch(Dispatchers.IO) 启动的协程的执行.

通过构造函数传递 Dispatcher 将确保您的测试和生产代码使用相同的调度程序。

通常 @Rule 定义为:

  1. 通过 Dispatchers.setMain 覆盖 MainDispatcher(就像你正在做的那样)
  2. 使用TestCoroutineDispatcher's自己的runBlockingTest()实际运行测试。

Here 是去年 Android 开发者峰会上关于测试和协程的精彩演讲。

here就是这样的一个例子@Rule。 (不要脸的插件。那个repo也有协程测试的例子)

我为使用 Dagger 的人编写此解决方案。

像这样在 ViewModel 构造函数中注入 CoroutineDispatcher:

class LoginViewModel @Inject constructor(val dispatcher: CoroutineDispatcher) : BaseViewModel() {

并像这样提供调度程序:

@Singleton
@Provides
fun provideDispatchers(): CoroutineDispatcher = Dispatchers.IO

在测试包中,像这样提供 Dispatcher:

@Singleton
@Provides
fun provideDispatchers(): CoroutineDispatcher = UnconfinedTestDispatcher()

现在 viewModelScope.launch(调度程序)中的所有行都将是 运行