【发布时间】:2021-06-30 20:29:49
【问题描述】:
完整的源代码在:https://github.com/AliRezaeiii/StarWarsSearch-RxPaging
这是我在使用协程进行网络时测试 ViewModel 的本地单元测试:
@Test
fun givenServerResponse200_whenFetch_shouldReturnSuccess() {
testCoroutineRule.runBlockingTest {
`when`(api.fetchShowList()).thenReturn(emptyList())
}
val repository = ShowRepository(dao, api, context, TestContextProvider())
testCoroutineRule.pauseDispatcher()
val viewModel = MainViewModel(repository)
assertThat(viewModel.shows.value, `is`(Resource.loading()))
testCoroutineRule.resumeDispatcher()
assertThat(viewModel.shows.value, `is`(Resource.success(emptyList())))
}
如您所知,我可以使用 TestCoroutineScope 暂停和恢复,因此我可以测试 liveData 何时处于 Loading 或 Success 状态。
我想知道我们是否可以在使用 RxJava 进行测试时做同样的事情。
目前我只能验证成功状态:
@Test
fun givenServerResponse200_whenFetch_shouldReturnSuccess() {
`when`(repository.getSpecie(anyString())).thenReturn(Single.just(specie))
`when`(repository.getPlanet(anyString())).thenReturn(Single.just(planet))
`when`(repository.getFilm(anyString())).thenReturn(Single.just(film))
viewModel = DetailViewModel(schedulerProvider, character,
GetSpecieUseCase(repository), GetFilmUseCase(repository))
viewModel.liveData.value.let {
assertThat(it, `is`(notNullValue()))
if (it is Resource.Success) {
it.data?.let { data ->
assertTrue(data.films.isNotEmpty())
assertTrue(data.species.isNotEmpty())
}
}
}
}
在 ViewModel 初始化块中,我发送网络请求。您可以在下面的课程中查看它。这可以在使用协程时使用暂停和恢复进行测试。 RxJava 怎么样?
open class BaseViewModel<T>(
private val schedulerProvider: BaseSchedulerProvider,
private val singleRequest: Single<T>
) : ViewModel() {
private val compositeDisposable = CompositeDisposable()
private val _liveData = MutableLiveData<Resource<T>>()
val liveData: LiveData<Resource<T>>
get() = _liveData
init {
sendRequest()
}
fun sendRequest() {
_liveData.value = Resource.Loading
singleRequest.subscribeOn(schedulerProvider.io())
.observeOn(schedulerProvider.ui()).subscribe({
_liveData.postValue(Resource.Success(it))
}) {
_liveData.postValue(Resource.Error(it.localizedMessage))
Timber.e(it)
}.also { compositeDisposable.add(it) }
}
override fun onCleared() {
super.onCleared()
compositeDisposable.clear()
}
}
【问题讨论】:
-
您可以在一定程度上使用
TestScheduler,但除非您在流程中设置了定时步骤,否则它将运行所有可用的工作。 -
感谢您的评论。正如我所理解的,使用 RxJava 的 TestScheduler 时,在您调用
advanceTimeBy()之前,时间是静止的,但是在sendRequest方法位于 ViewModel 的 init 块中的情况下,它如何工作。您能否使用您在我的案例中推荐的代码来解释您的建议作为答案。如您所见,我没有Observable.interval,我不想测试我的代码中的延迟或超时是否按预期工作。 -
使
schedulerProvider.ui()和schedulerProvider.io()返回一个您也可以引用的TestScheduler,然后将testCoroutineRule.resumeDispatcher()替换为testScheduler.advanceTimeBy(1, TimeUnit.SECONDS)。 -
我试过了。如果我返回 TestScheduler,所有测试用例都将通过而不检查断言中实际值和预期值的结果。那是我错过的吗? Here 是我的测试用例。
-
你改用我建议的
TestScheduler的代码在哪里?
标签: android unit-testing rx-java rx-java2 kotlin-coroutines