RxJava, как проверить debounce? - PullRequest
       8

RxJava, как проверить debounce?

0 голосов
/ 12 февраля 2019

Я пытаюсь проверить оператор "debounce" в Android RxJava2.

Я использовал оператор "debounce" для функции поиска.

В представлении (активность) поиск выполняетсязапущен.

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 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» вызывается ...

Пожалуйста, знаете, почему?

1 Ответ

0 голосов
/ 13 февраля 2019

Чтобы быстро пройти тестовый код, просто измените несколько вещей.

  1. Используйте TestScheduler
  2. Разделите планировщик ui и io.
  3. Используйте 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 https://stackoverflow.com/a/53543257/1355048
        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)
    }
}
...