RxJava中类似TestCoroutineScope暂停和恢复的解决方法
Solution to pause and resume in RxJava similar to TestCoroutineScope
完整的源代码可在以下位置获得: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 何时处于加载或成功状态。
我想知道我们在使用 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 初始化块中,我发送了网络请求。您可以在下方查看 class。这可以在使用协程时使用暂停和恢复进行测试。 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
:
class ImmediateSchedulerProvider : BaseSchedulerProvider {
val testScheduler = TestScheduler()
override fun computation(): Scheduler = testScheduler
override fun io(): Scheduler = testScheduler
override fun ui(): Scheduler = testScheduler
}
单元测试并没有因为错误的状态而失败,所以即使代码没有,它们似乎也通过了 运行:
@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),
GetPlanetUseCase(repository), GetFilmUseCase(repository))
viewModel.liveData.value.let {
assertThat(it, `is`(Resource.Loading))
}
schedulerProvider.testScheduler.advanceTimeBy(1, TimeUnit.MILLISECONDS) // <-------------
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())
}
} else {
fail("Wrong type " + it) // <---------------------------------------------
}
}
}
完整的源代码可在以下位置获得: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 何时处于加载或成功状态。
我想知道我们在使用 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 初始化块中,我发送了网络请求。您可以在下方查看 class。这可以在使用协程时使用暂停和恢复进行测试。 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
:class ImmediateSchedulerProvider : BaseSchedulerProvider { val testScheduler = TestScheduler() override fun computation(): Scheduler = testScheduler override fun io(): Scheduler = testScheduler override fun ui(): Scheduler = testScheduler }
单元测试并没有因为错误的状态而失败,所以即使代码没有,它们似乎也通过了 运行:
@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), GetPlanetUseCase(repository), GetFilmUseCase(repository)) viewModel.liveData.value.let { assertThat(it, `is`(Resource.Loading)) } schedulerProvider.testScheduler.advanceTimeBy(1, TimeUnit.MILLISECONDS) // <------------- 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()) } } else { fail("Wrong type " + it) // <--------------------------------------------- } } }