Наблюдаемая RxJava выполнена, но обратный вызов doOnComplete не запущен в модульном тесте - PullRequest
0 голосов
/ 02 января 2019

У меня есть следующая логика для создания наблюдаемых данных из завершаемых (с обратным вызовом doOnComplete), который тестируется модулем:

class ObservableSrc(val completableSrc: CompletableSrc) {

    fun getObservable(client: Client): Observable<State> {
        return client.getResults()
            .concatMap { processResult(client, it.values) }
    }

    private fun processResult(Client: Client, values: Values): Observable<State> =
        completableSrc.getCompletable(client.type, values)
            .doOnComplete { client.doSomething(values)}
            .toSingleDefault(…)
            .map { … }
            .toObservable()
            .startWith(State.InProgress)
}

@Test
fun test() {
    whenever(client.type).doReturn(Type.SOME_TYPE)
    whenever(client.getResults()).doReturn(Observable.just<Result>(Result(mock())))
    whenever(completableSrc.getCompletable(any(), any())).doReturn(Completable.complete())
    doNothing().whenever(client).doSomething(any())

    val observer = tested.getObservable(client).test()

    observer.assertComplete()
    verify(completableSrc, times(1)).getCompletable(any(), any())
    verify(client, times(1)).doSomething(any())
}

Проблема в том, что проверка doSomething дает, что было 2 взаимодействияс макетом client, но нужный метод не был вызван.Я обнаружил, что если я немного поменяю цепочку следующим образом:

completableSrc.getCompletable(client.type, values)
                .toSingleDefault(…)
                .map { … }
                .doOnSuccess { client.doSomething(values)}
                .toObservable()
                .startWith(State.InProgress)

, то это работает.Я просто не знаю, почему предыдущая версия с doOnComplete не работает (observer.assertComplete() успешно выполняется).Кажется, что он утилизируется слишком рано, поэтому обратный вызов не вызывается, но почему?

1 Ответ

0 голосов
/ 03 января 2019

Обновление

Проверка кода с использованием модульного теста и проверок.Я использую kolin.test и mockk для личных предпочтений.

interface CompletableSrc {
    fun getCompletable(): Completable
}

interface Client {
    fun doSomething()
    fun doSomethingElse()
}

class CompletableTest {

    @Test
    fun `functions doOnComplete and doOnSuccess should work as expected`() {
        val completableSrc: CompletableSrc = mockk {
            every { getCompletable() } returns Completable.complete()
        }

        val client: Client = mockk {
            every { doSomething() } returns Unit
            every { doSomethingElse() } returns Unit
        }

        val observable = completableSrc.getCompletable()
            .doOnComplete { client.doSomething() }
            .toSingleDefault(0)
            .map { it + 1 }
            .doOnSuccess { client.doSomethingElse() }
            .toObservable()
            .startWith(-1)

        val test = observable.test()
        test.assertComplete()
        test.assertValues(-1, 1)

        verify(exactly = 1) {
            completableSrc.getCompletable()
            client.doSomething()
            client.doSomethingElse()
        }
    }
}

Как видите, как утверждения, так и фиктивные проверки завершились успешно.

Предыдущий

Ваш код должен работать нормально, для меня действительно трудно сказать, что не так, потому что я не могу его запустить, но я создаю фрагмент, который в значительной степени выполняеттоже самое и работает как положено.

Пример

fun main(args: Array<String>) {
    var sideEffect = 0

    val observable = Completable.complete()
        .doOnComplete { sideEffect += 1 }
        .toSingleDefault(sideEffect)
        .map { sideEffect + 1 }
        .doOnSuccess(::println)
        .toObservable()
        .startWith(-1)

    val test = observable.test()
    test.assertComplete()
    test.assertValues(-1, 2)
}

Вывод

2

Оба побочных эффектавыполняются функции Completable.doOnComplete и Single.doOnSuccess, обновление переменной sideEffect и печать в консоль.

...