使用 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.setMain
将 TestCorotutineDispatcher
设置为主调度程序,它控制 MainDispatcher
,但您仍然无法控制通过 viewModelScope.launch(Dispatchers.IO)
启动的协程的执行.
通过构造函数传递 Dispatcher
将确保您的测试和生产代码使用相同的调度程序。
通常 @Rule
定义为:
- 通过
Dispatchers.setMain
覆盖 MainDispatcher(就像你正在做的那样)
- 使用
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(调度程序)中的所有行都将是 运行
所以也许有一个教程讨论了这个问题,但是 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.setMain
将 TestCorotutineDispatcher
设置为主调度程序,它控制 MainDispatcher
,但您仍然无法控制通过 viewModelScope.launch(Dispatchers.IO)
启动的协程的执行.
通过构造函数传递 Dispatcher
将确保您的测试和生产代码使用相同的调度程序。
通常 @Rule
定义为:
- 通过
Dispatchers.setMain
覆盖 MainDispatcher(就像你正在做的那样) - 使用
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(调度程序)中的所有行都将是 运行