RxJava 如何测试去抖?
RxJava how to test debounce?
我正在尝试在 Android.
中测试 RxJava2 的 "debounce" 运算符
我在搜索功能中使用了 "debounce" 运算符。
在视图(Activity)中,开始搜索。
etSearch.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(editable: Editable) {
mPresenter.search(editable.toString())
}
...
})
主持人在这里:
class MyPresenter(
private val view: MyContract.View,
private val apiService: ApiServie = ApiServiceImpl(),
private val searchSubject: PublishSubject<String> = PublishSubject.create(),
var debounceScheduler: Scheduler = Schedulers.computation()
) : MyContract.Presenter {
init {
setupSearch()
}
override fun search(keyword: String) {
if (searchDisposable.size() == 0) {
setupSearch()
}
searchSubject.onNext(keyword)
}
private fun setupSearch() {
searchSubject.debounce(1000, TimeUnit.MILLISECONDS, debounceScheduler)
.distinctUntilChanged()
.switchMap { keyword ->
apiService.search(keyword)
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { response ->
response.data?.let { data ->
view.searchResult(data)
}
}
}
}
实际上,当我进行集成测试时,它工作正常。
但我想做的是测试 MyPresenter class.
的 "search" 功能
为此,我阅读了 article
但是没用...
我的测试代码在这里:
class MyTest {
@Mock
private lateinit var mockView: MyContract.View
@Mock
private lateinit var mockApiService: ApiService
private lateinit var mMyPresenter: MyPresenter
private lateinit var inOrder: InOrder
private val mTestScheduler: TestScheduler = TestScheduler()
private val ZERO = 0
private fun setUpScheduler() {
val immediate = object : Scheduler() {
override fun createWorker() = ExecutorScheduler.ExecutorWorker(Runnable::run)
}
RxJavaPlugins.setInitIoSchedulerHandler { immediate }
RxAndroidPlugins.setInitMainThreadSchedulerHandler { immediate }
}
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
setUpScheduler()
mMyPresenter = MyPresenter(mockView, mockApiService)
inOrder = inOrder(mockView)
}
@Test
fun searchBillsTest() {
`when`(mockApiService.search("America"))
.thenReturn(Observable.just(mockResult))
mMyPresenter.debounceScheduler = mTestScheduler
mMyPresenter.search("America")
mTestScheduler.advanceTimeBy(1000, TimeUnit.MILLISECONDS)
verify(mockView).searchResult(mockResult)
}
}
上次验证未调用...
我不知道为什么...
我添加了 "doOnNext" 来打印日志以查找 "searchSubject" 中的原因,但是 "doOnNext" 没有被调用...
"doOnSubscribe" 被称为...
请问你知道为什么吗?
为了尽快通过您的测试代码,只需更改几处即可。
- 使用测试调度程序
- 划分
ui
和 io
调度程序。
- 在主题的触发事件之前使用
Scheduler.triggerActions
。
@RunWith(MockitoJUnitRunner::class)
class DebounceTest {
private lateinit var searchSubject: PublishSubject<String>
@Mock lateinit var apiService: ApiService
@Mock lateinit var presenter: Presenter
private lateinit var disposable: Disposable
private lateinit var ioTestScheduler: TestScheduler
private lateinit var uiTestScheduler: TestScheduler
@Before fun setUp() {
searchSubject = PublishSubject.create<String>()
ioTestScheduler = TestScheduler()
uiTestScheduler = TestScheduler()
setupSearch(uiTestScheduler, ioTestScheduler)
// important
ioTestScheduler.triggerActions()
}
@After fun tearDown() {
disposable.dispose()
}
@Test fun searchBillsTest() {
`when`(apiService.search("America")).thenReturn(Observable.just("MOCK RESULT"))
searchSubject.onNext("America")
ioTestScheduler.advanceTimeBy(1, TimeUnit.SECONDS)
uiTestScheduler.triggerActions()
verify(presenter).doSomething("MOCK RESULT")
}
private fun setupSearch(uiScheduler: Scheduler, ioScheduler: Scheduler) {
disposable = searchSubject.debounce(1, TimeUnit.SECONDS, ioScheduler)
.distinctUntilChanged()
.switchMap { apiService.search(it) }
.subscribeOn(ioScheduler)
.observeOn(uiScheduler)
.subscribe { response ->
presenter.doSomething(response)
}
}
interface ApiService {
fun search(query: String): Observable<String>
}
interface Presenter {
fun doSomething(result: String)
}
}
我正在尝试在 Android.
中测试 RxJava2 的 "debounce" 运算符我在搜索功能中使用了 "debounce" 运算符。
在视图(Activity)中,开始搜索。
etSearch.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(editable: Editable) {
mPresenter.search(editable.toString())
}
...
})
主持人在这里:
class MyPresenter(
private val view: MyContract.View,
private val apiService: ApiServie = ApiServiceImpl(),
private val searchSubject: PublishSubject<String> = PublishSubject.create(),
var debounceScheduler: Scheduler = Schedulers.computation()
) : MyContract.Presenter {
init {
setupSearch()
}
override fun search(keyword: String) {
if (searchDisposable.size() == 0) {
setupSearch()
}
searchSubject.onNext(keyword)
}
private fun setupSearch() {
searchSubject.debounce(1000, TimeUnit.MILLISECONDS, debounceScheduler)
.distinctUntilChanged()
.switchMap { keyword ->
apiService.search(keyword)
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { response ->
response.data?.let { data ->
view.searchResult(data)
}
}
}
}
实际上,当我进行集成测试时,它工作正常。 但我想做的是测试 MyPresenter class.
的 "search" 功能为此,我阅读了 article
但是没用...
我的测试代码在这里:
class MyTest {
@Mock
private lateinit var mockView: MyContract.View
@Mock
private lateinit var mockApiService: ApiService
private lateinit var mMyPresenter: MyPresenter
private lateinit var inOrder: InOrder
private val mTestScheduler: TestScheduler = TestScheduler()
private val ZERO = 0
private fun setUpScheduler() {
val immediate = object : Scheduler() {
override fun createWorker() = ExecutorScheduler.ExecutorWorker(Runnable::run)
}
RxJavaPlugins.setInitIoSchedulerHandler { immediate }
RxAndroidPlugins.setInitMainThreadSchedulerHandler { immediate }
}
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
setUpScheduler()
mMyPresenter = MyPresenter(mockView, mockApiService)
inOrder = inOrder(mockView)
}
@Test
fun searchBillsTest() {
`when`(mockApiService.search("America"))
.thenReturn(Observable.just(mockResult))
mMyPresenter.debounceScheduler = mTestScheduler
mMyPresenter.search("America")
mTestScheduler.advanceTimeBy(1000, TimeUnit.MILLISECONDS)
verify(mockView).searchResult(mockResult)
}
}
上次验证未调用... 我不知道为什么... 我添加了 "doOnNext" 来打印日志以查找 "searchSubject" 中的原因,但是 "doOnNext" 没有被调用... "doOnSubscribe" 被称为...
请问你知道为什么吗?
为了尽快通过您的测试代码,只需更改几处即可。
- 使用测试调度程序
- 划分
ui
和io
调度程序。 - 在主题的触发事件之前使用
Scheduler.triggerActions
。
@RunWith(MockitoJUnitRunner::class)
class DebounceTest {
private lateinit var searchSubject: PublishSubject<String>
@Mock lateinit var apiService: ApiService
@Mock lateinit var presenter: Presenter
private lateinit var disposable: Disposable
private lateinit var ioTestScheduler: TestScheduler
private lateinit var uiTestScheduler: TestScheduler
@Before fun setUp() {
searchSubject = PublishSubject.create<String>()
ioTestScheduler = TestScheduler()
uiTestScheduler = TestScheduler()
setupSearch(uiTestScheduler, ioTestScheduler)
// important
ioTestScheduler.triggerActions()
}
@After fun tearDown() {
disposable.dispose()
}
@Test fun searchBillsTest() {
`when`(apiService.search("America")).thenReturn(Observable.just("MOCK RESULT"))
searchSubject.onNext("America")
ioTestScheduler.advanceTimeBy(1, TimeUnit.SECONDS)
uiTestScheduler.triggerActions()
verify(presenter).doSomething("MOCK RESULT")
}
private fun setupSearch(uiScheduler: Scheduler, ioScheduler: Scheduler) {
disposable = searchSubject.debounce(1, TimeUnit.SECONDS, ioScheduler)
.distinctUntilChanged()
.switchMap { apiService.search(it) }
.subscribeOn(ioScheduler)
.observeOn(uiScheduler)
.subscribe { response ->
presenter.doSomething(response)
}
}
interface ApiService {
fun search(query: String): Observable<String>
}
interface Presenter {
fun doSomething(result: String)
}
}