如何测试RxSwift变量和RxCocoa Observable之间的UI绑定?

时间:2018-02-15 17:26:54

标签: ios swift unit-testing rx-swift rx-cocoa

我有一个简单的ViewModel,其中包含一个属性:

class ViewModel {
    var name = Variable<String>("")
}

我将UITextField绑定到ViewController

class ViewController : UIViewController {

    var viewModel : ViewModel!

    @IBOutlet weak var nameField : UITextField!

    private let disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()
        // Binding
        nameField.rx.text
            .orEmpty
            .bind(to: viewModel.name)
            .disposed(by: disposeBag)
    }
}

现在,我想进行单元测试。

我可以使用nameField.text事件 - .onNext通过Rx填充nameField.rx.text.onNext("My Name Here")媒体资源。

viewModel.name并未被填补。为什么?如何在我的XCTestCase中使这个Rx行为起作用?

请参阅下面我上次测试的结果:

Last Test Run Screenshot

2 个答案:

答案 0 :(得分:2)

我相信您遇到的问题是绑定未在主线程上明确安排。我建议在这种情况下使用Driver

class ViewModel {
  var name = Variable<String>("")
}

class ViewController: UIViewController {

  let textField = UITextField()
  let disposeBag = DisposeBag()
  let vm = ViewModel()

  override func viewDidLoad() {
    super.viewDidLoad()
    textField.rx.text
        .orEmpty
        .asDriver()
        .drive(vm.name)
        .disposed(by: disposeBag)
}

// ..

使用Driver,绑定将始终发生在主线程上,并且不会出错。

另外,在你的测试中,我会在绑定上调用skip

sut.nameTextField.rx.text.skip(1).onNext(name)

因为Driver会在订阅时重播第一个元素。

最后,我建议使用RxTest和TestScheduler代替GCD。

如果有帮助,请告诉我。

答案 1 :(得分:0)

rx.text依赖于以下UIControlEvent:.allEditingEvents.valueChanged。因此,显式发送onNext事件将不会为这些事件发送动作。您应该手动发送操作。

sut.nameField.rx.text.onNext(name)
sut.nameField.sendActions(for: .valueChanged)