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

Posted

技术标签:

【中文标题】如何测试 RxSwift 变量和 RxCocoa Observable 之间的 UI 绑定?【英文标题】:How to test the UI Binding between RxSwift Variable and RxCocoa Observable? 【发布时间】:2018-02-15 17:26:54 【问题描述】:

我有一个简单的ViewModel 有一个属性:

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

我将它绑定到我的ViewController 中的UITextField

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)
    

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

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

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

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

【问题讨论】:

UI 组件在尝试进行单元测试时几乎总是会出现问题,这就是它们不适合这项任务的原因。改为测试您的业务逻辑,并让 QA 进行 UI 检查。 好电话@Cristik,我会听取你的建议。我仍然很好奇为什么 Rx 没有被解雇 我推荐使用 RxTest 库和TestScheduler 而不是 GCD。然后,您可以在特定团队安排行动,并且您拥有更多控制权。 另外Variable 已被弃用。您可以使用 BehaviorRelayPublishRelay 作为替代品。 【参考方案1】:

我相信您遇到的问题是绑定没有明确安排在主线程上。在这种情况下,我建议使用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。

如果这有帮助,请告诉我。

【讨论】:

【参考方案2】:

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

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

【讨论】:

以上是关于如何测试 RxSwift 变量和 RxCocoa Observable 之间的 UI 绑定?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 UITableView 的 RXswift 和 RXCocoa 中实现 tableview 单元格的内部?

Swft3 (RxSwift, RxCocoa) - TableView 使用响应式编程展开和折叠概念

RxSwift、RxCocoa 和 UITableview

在 RxCocoa/RxSwift 中,如何观察 BehaviorRelay<[object]> 数组大小发生变化

使用 RxSwift 和 RXCocoa 验证按钮单击时的所有文本字段

处理 UITableView 绑定中的连接错误(Moya、RxSwift、RxCocoa)