首页 > 解决方案 > 如何断言使用最新文本输入的可观察对象的输出

问题描述

我的视图模型上有一个属性:

    let isValid: Driver<Bool>
    let credentials: Driver<(String, String)>
......
        credentials = .combineLatest(bindings.username, bindings.password, resultSelector: { (username, password) -> (String, String) in (username, password) })

        isValid = credentials.map { username, password in username.count > 0 && password.count > 7 }

我想断言在设置isValid有效输入时设置了正确的状态。

我的测试在下面通过,但这感觉不是测试这种情况的正确方法。

理想情况下,我想从我的字符串 as 开始"",然后像输入它们一样传入值,这样我就可以断言默认状态已设置然后更改。

我还发现这些行:

   .do(onNext: { state in
            if state {
                exp.fulfill()
            }
        })

有点“hacky”。

   func test_is_valid_state_changes_when_inputs_correct_length() {

        let username: Driver<String> = .of("some_user_name")
        let password: Driver<String> = .of("some_user_password")

        let bindings = LoginViewModel.Bindings(username: username, password: password, loginTap: .empty(), doneTap: .empty())
        let sut = LoginViewModel(dependency: "", bindings: bindings)

        let scheduler = TestScheduler(initialClock: 0)
        let observer = scheduler.createObserver(Bool.self)

        let exp = expectation(description: "isValid Event")

        sut.isValid
            .asObservable()
            .do(onNext: { state in
                if state {
                    exp.fulfill()
                }
            })
            .subscribe(observer)
            .disposed(by: disposeBag)

        scheduler.start()

        waitForExpectations(timeout: 0.5) { error in
            XCTAssertNil(error)
            XCTAssertEqual(observer.events.count, 1)
            XCTAssertTrue(observer.events[0].value.element!) // swiftlint:disable:this force_unwrapping
        }
    }

标签: swiftreactive-programmingxctestrx-swiftrxtest

解决方案


您需要使用 TestObservables 来进行所需的测试,并且不需要期望对象,因为此测试将在没有任何线程问题的情况下完成。

    func test_is_valid_state_changes_when_inputs_correct_length() {
        let scheduler = TestScheduler(initialClock: 0)

        let username = scheduler.createHotObservable([.next(0, ""), .next(10, "h")])
        let password = scheduler.createHotObservable([.next(0, ""), .next(30, "p"), .next(40, "passwor"), .next(50, "password")])

        let bindings = LoginViewModel.Bindings(
            username: username.asDriver(onErrorRecover: { _ in XCTFail(); return .empty() }),
            password: password.asDriver(onErrorRecover: { _ in XCTFail(); return .empty() }),
            loginTap: .empty(),
            doneTap: .empty()
        )
        let disposeBag = DisposeBag()
        let sut = LoginViewModel(dependency: "", bindings: bindings)

        let observer = scheduler.createObserver(Bool.self)

        sut.isValid
            .drive(observer)
            .disposed(by: disposeBag)

        scheduler.start()

        XCTAssertEqual(observer.events, [
            .next(0, false),
            .next(10, false),
            .next(30, false),
            .next(40, false),
            .next(50, true)
        ])

    }

推荐阅读