swift - 如何使用 RxSwift 和 XCTest 测试进入 Swift 主线程的函数?

标签 swift unit-testing mvvm rx-swift

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

在我的 ViewModel 中,我调用异步操作,当响应到达时,我使用 PublishSubject 在我的 View 中产生变化。在我的 View 中,我调用 DispatchQueue.main.async 以隐藏或显示按钮。

View 模型

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 中而不是在 View 中调度主队列,这对我来说听起来很奇怪,但我可能没问题。

我该如何解决这个问题? 提前谢谢你。

最佳答案

您可以在单元测试中使用基于谓词的异步期望来等待按钮是否不再隐藏。

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。这是因为类是通过引用传递的,所以谓词 block 内的值将与 View 模型所触及的值相同。但是,如果您要传递一个 structenum,它们是通过副本传递的,则谓词 block 将收到该值的副本,因为它是在运行设置代码,它总是会失败。

如果您更喜欢按照@Randall Wang 在他的回答中的建议使用 UI 测试,那么这篇文章可能对您有用:“How to test UI changes in Xcode 7 ”。 完全公开,那篇文章是我写的。

关于swift - 如何使用 RxSwift 和 XCTest 测试进入 Swift 主线程的函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42814478/

相关文章:

swift - 触发 CombineLatest 在 Combine 中传播初始值

Swift:导出依赖的API

iphone - OCUnit 测试 NSNotification 传递

android - Android 中的 MVVM 存储库

ios - Swift:功能完成的顺序是不可预测的

html - 将字体属性添加到 HTML 渲染的 UILabel swift

java - 我无法将 Mockito 单元测试重写为 Spock 规范

java - 程序中途掉网测试效果

wpf - 我可以实现自己的 View 解析服务并让 RequestNavigate 使用它吗?

mvvm - 在 MVVM 中,谁创建 View 、 View 模型和模型?谁将它们连接在一起?