【问题标题】:How to test a function that gets into the main thread in Swift with RxSwift and XCTest?如何使用 RxSwift 和 XCTest 测试进入 Swift 主线程的函数?
【发布时间】:2017-03-15 15:43:16
【问题描述】:

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

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

视图模型

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

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

【问题讨论】:

    标签: swift unit-testing mvvm rx-swift


    【解决方案1】:

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

    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 测试,那么这篇文章可能对您有用:“How to test UI changes in Xcode 7”。 完全披露,我写了那篇文章。

    【讨论】:

    • 此解决方案完美运行。非常感谢您的帮助和时间!
    • 我很高兴@Jefe55,很高兴能提供帮助:)
    【解决方案2】:

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

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

    这里是 UI 测试的 WWDC。

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

    【讨论】:

    • 我想我的问题表述不正确。我的目的不是测试方法本身,而是以某种方式测试操作的结果。绝对 UI 测试是一个不错的选择。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2019-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-20
    • 1970-01-01
    相关资源
    最近更新 更多