如何通过rxswift和xctest测试进入Swift中主线程的函数



我在测试我的视图时遇到了这个问题:

在我的ViewModel中,我称之为异步操作,当响应到达时,我使用PublishSubject在视图中产生更改。在我看来,我致电DispatchQueue.main.async以隐藏或显示一个按钮。

ViewModel

let refreshButtons = PublishSubject<Bool>(true)
refreshButtons.onNext(true)

查看

model.refreshButtons.asObservable()
                .subscribe(onNext: {
                    [unowned self] success in
                    self.updateButtons(success)
                })
                .addDisposableTo(disposable)
private func updateButtons(_ show:Bool) {
   DispatchQueue.main.async{
      button.isHidden = !show
   }
}

现在,我不知道如何单位测试refreshButtons.onNext(true)将隐藏或显示我的按钮。

我能想到的解决方案是:

  • 覆盖该方法并具有异步期望,但是为此,我需要将方法公开,我不想要的东西或
  • 在我的ViewModel中派遣主要队列,而不是在视图中,这听起来对我来说很奇怪,但我可能还可以。

我该如何解决?预先感谢您。

您可以根据单元测试中的谓词使用异步期望来等待一个按钮是否不隐藏。

func testButtonIsHidden() {
  // Setup your objects
  let view = ...
  let viewModel = ...
  // Define an NSPredicate to test your expectation
  let predicate = NSPredicate(block: { input, _ in
    guard let _view = input as? MyView else { return false }
    return _view.button.isHidden == true
  })

  // Create an expectation that will periodically evaluate the predicate 
  // to decided whether it's fulfilled or not
  _ = expectation(for: predicate, evaluatedWith: view, handler: .none)
  // Call the method that should generate the behaviour you are expecting.
  viewModel.methodThatShouldResultInButtonBeingHidden()
  // Wait for the 
  waitForExpectationsWithTimeout(1) { error in
    if let error = error {
      XCTFail("waitForExpectationsWithTimeout errored: (error)")
    }
  }
}

值得注意的是,您传递给NSPredicate的值应该是class。这是因为类是通过引用传递的,因此谓词块内部的值与您的视图模型触摸的值相同。如果您要通过structenum(通过复制传递),则谓词块将接收值的副本,就像运行设置代码时一样,它将始终失败。

相反,如果您更喜欢按照@randall Wang在答案中建议的UI测试,那么这篇文章可能对您有用:"如何在Xcode 7中测试UI更改"。全面披露,我写了那篇文章。

首先,您不需要测试私有方法

如果要测试按钮是否隐藏,请尝试UI测试

这是UI测试的WWDC。

https://developer.apple.com/videos/play/wwdc2015/406/

最新更新