Запустить событие и ждать нескольких событий RxTest - PullRequest
1 голос
/ 25 июня 2019

Я впервые использую RxTest , и я изо всех сил пытаюсь сделать следующий подход:

protocol ViewModelType {
    func transform(input: ViewModel.Input) -> ViewModel.Output
}

struct ViewModel: ViewModelType {
    private let isLoading = PublishSubject<Bool>()

    struct Input {
        let trigger: PublishSubject<Void>
    }

    struct Output {
        let someAction: Observable<Void>
        let isLoading: Observable<Bool>
    }

    func transform(input: Input) -> Output {
        let someAction = input
            .trigger
            .do(onNext: { _ in
                self.isLoading.onNext(true)
                //do some async task
                self.isLoading.onNext(false)
            })
        return Output(someAction: someAction, isLoading: isLoading)
    }
}

Я создал тему публикации внутри viewModel, чтобы уведомить представление, когда онодолжен показывать загрузчик или нет.

Все работает нормально, за исключением того, что я не знаю, как проверить это с помощью инфраструктуры RxTest.

Я пытался использовать планировщик и холодные наблюдаемые, но не смогне удалось заставить его работать.

То, что я хотел бы получить:

  1. С помощью планировщика отправьте .next (10, ()) в триггер.
  2. Каким-то образом запишите события isLoading и assert равные, которые идут сначала в true, а затем в false.Вот так: [.next (10, true), .next (20, false)].

Может быть, isLoading, как я это сделал, не тестируется.Но, похоже, он проходит через вывод. Я думаю, что, возможно, есть какой-то способ.

Большое спасибо, если что-то неясно, пожалуйста, не стесняйтесь редактировать или направлять меня к лучшему вопросу.Очень ценится.

1 Ответ

1 голос
/ 25 июня 2019

Пара вещей:

Ваша Input структура должна содержать Observables, а не предметы. Таким образом, вы можете прикрепить к ним правильно.

Вы не хотите использовать оператор do. Вместо этого сначала подумайте о проблеме из выходных данных. Когда срабатывает триггер, вы хотите, чтобы isLoading излучал true, и вы хотите, чтобы асинхронная задача запускалась. Это означает, что у вас должно быть две наблюдаемые цепочки. Там много примеров кода, показывающих, как это сделать.

А пока вот ваш тест (вместе с необходимыми изменениями в вашем коде:


class RxSandboxTests: XCTestCase {

    func testOne() {

        let scheduler = TestScheduler(initialClock: 0)
        let trigger = scheduler.createHotObservable([.next(10, ())])
        let someActionResult = scheduler.createObserver(Bool.self)
        let isLoadingResult = scheduler.createObserver(Bool.self)
        let bag = DisposeBag()
        let sut = ViewModel()
        let input = ViewModel.Input(trigger: trigger.asObservable())
        let output = sut.transform(input: input)

        bag.insert(
            output.someAction.map { true }.bind(to: someActionResult),
            output.isLoading.bind(to: isLoadingResult)
        )
        scheduler.start()

        XCTAssertEqual(someActionResult.events, [.next(10, true)])
        XCTAssertEqual(isLoadingResult.events, [.next(10, true), .next(10, false)])
    }

}

protocol ViewModelType {
    func transform(input: ViewModel.Input) -> ViewModel.Output
}

struct ViewModel: ViewModelType {
    private let isLoading = PublishSubject<Bool>()

    struct Input {
        let trigger: Observable<Void>
    }

    struct Output {
        let someAction: Observable<Void>
        let isLoading: Observable<Bool>
    }

    func transform(input: Input) -> Output {
        let someAction = input
            .trigger
            .do(onNext: { _ in
                self.isLoading.onNext(true)
                //do some async task
                self.isLoading.onNext(false)
            })
        return Output(someAction: someAction, isLoading: isLoading)
    }
}

...