onNext没有被称为单元测试RxCocoa驱动程序

时间:2017-03-01 17:39:22

标签: swift rx-swift rx-cocoa

我正在尝试从RxCocoa库中为Driver编写单元测试。这是我的简化实现代码:

struct LoginViewModel {

    var username: Driver<String?>!
    var password: Driver<String?>!
    var loginTaps: Driver<Void>!

    func login() -> Driver<LoginResult> {
        let credentials = Driver.combineLatest(username, password) { ($0, $1) }
        let latestCredentials = loginTaps.withLatestFrom(credentials)

        return latestCredentials.flatMapLatest { (username, password) in
            .just(.success)
        }
    }
}

这是我试图通过的Quick / Nimble单元测试:

let disposeBag = DisposeBag()
var capturedLoginResult = LoginResult.failed

loginViewModel.username = Driver.just("some username")
loginViewModel.password = Driver.just("some password")
loginViewModel.loginTaps = Driver.just()

loginViewModel.login().drive(onNext: { loginResult in
    capturedLoginResult = loginResult
}).addDisposableTo(disposeBag)

expect(capturedLoginResult == .success)

以上expect表示capturedLoginResult仍为.failed。似乎return latestCredentials.flatMapLatest { (username, password) in .just(.success) }中的.drive(onNext: )元素未在测试中被login收到。

如果func login() -> Driver<LoginResult> { return .just(.success) } 的实施只是:

let app = require('../src/app').default;

测试通过。

有关这里发生的事情的任何想法?谢谢!

1 个答案:

答案 0 :(得分:1)

我不确切知道Rx源代码的确切位置,但我的猜测是您正在使用的运算符是切换调度程序。因此,使用drive(onNext:)进行的订阅不会立即触发。

RxSwift通过RxTest包为测试我们的observable提供了一个很好的API。您可以重写测试以利用它。

let scheduler = TestScheduler(initialClock: 0)
let username = scheduler.createHotObservable([next(220, "username"), completed(20)])
let password = scheduler.createHotObservable([next(230, "p4ssw0rd"), completed(20)])
let loginTaps = scheduler.createHotObservable([next(240), completed(20)]) 

let recordObserver = scheduler.start(300) { () -> Observable<LoginResult> in
  let loginViewModel = LoginViewModel()

  loginViewModel.username = username.asDriver(onErrorJustReturn: "")
  loginViewModel.password = username.asDriver(onErrorJustReturn: "")
  loginViewModel.loginTaps = loginTaps.asDriver(onErrorJustReturn: ())

  return loginViewModel.login().asObservable()
}

let expectedEvents: [Recorded<Event<LoginResult>>] = [
  next(240, Login.success)
]

expect(recordObserver.events) == (expectedEvents)