1

我有一个简单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通过 Rx 使用.onNextevent -填充属性nameField.rx.text.onNext("My Name Here")

但是viewModel.name没有被填满。为什么?如何使这种 Rx 行为在我的 XCTestCase 中起作用?

请看下面我上次测试运行的结果:

上次测试运行屏幕截图

4

2 回答 2

2

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

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)
}

// ..

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

另外,在您的测试中,我会调用skip绑定:

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

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

最后,我建议使用 RxTest 和 aTestScheduler而不是 GCD。

让我知道这是否有帮助。

于 2018-02-15T22:19:58.907 回答
1

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

sut.nameField.rx.text.onNext(name)
sut.nameField.sendActions(for: .valueChanged)
于 2019-09-17T18:10:22.597 回答