【问题标题】:iOS - Unit Testing asynchronous private function in Presenter of MVPiOS - MVP 演示者中的单元测试异步私有函数
【发布时间】:2018-10-11 13:14:25
【问题描述】:

您好,我正在尝试对位于 Presenter 中的私有函数进行单元测试

这是我的演示者代码,我正在使用网络单例对象APIService

class MyPresenter {
  weak var vc: MyProtocol?

  func attachView(vc: MyProtocol?) {
     self.vc = vc
  }

  func request(_ id: String) {
    if id.count == 0 {
      vc?.showIDEmptyAlert()
      return
    }
    fetch(id)
  }

  private func fetch(_ id:String) {
    DispatchQueue.global.async {
      APIService.shared.fetch(id) { (data, err) in 
        if let err = err {
          self.vc?.showErrorAlert()
          return
        }
        self.vc?.update(data)
      }
    }
  }
}

这是我的 ViewController 代码

class MyViewController: UIViewController, MyProtocol {
  private var presenter: MyPresenter = MyPresenter()

  override func viewDidLoad() {
    super.viewDidLoad()
    presenter.attachView(vc: self)
  }

  func showIDEmptyAlert() {
    self.present .. 
  }

  func showErrorAlert() {
    self.present .. 
  }

  func update(data: String) {
    self.label.text = data 
  }

  @IBAction func handleRegisterButton(_ sender: UIButton) {
    guard let id = idTextField.text else { return }
    presenter.request(id)
  }
}

这些是我的演示者和视图。我写了这样的测试代码

首先,我制作了这样的 Mock PassiveView

class MyViewMock: MyProtocol {
  private (set) var showEmptyIdAlertHasBeenCalled = false
  private (set) var showErrorAlertHasBeenCalled = false
  private (set) var updateHasBeenCalled = false

  func showEmptyIdAlert() {
    showEmptyIdAlertHasBeenCalled = true
  }
  func showErrorAlert() {
    showErrorAlertHasBeenCalled = true
  }
  func update(data: String) {
    updateHasBeenCalled = true
  }

}

所以我希望如果我可以用有效 id 和无效来测试 Presenter 的 request(_:) 方法

但是因为request(_:) 没有获取handler 参数并且APIService.shared.fetch 是异步的,所以我无法获取 通过调用request(_:) 得到正确结果。 (总是假的)

如何测试这种 Presenter?

【问题讨论】:

    标签: ios swift unit-testing mvp presenter


    【解决方案1】:

    XCTests方面,有XCTestExpectation类来测试异步函数。 但是您测试演示者的方法存在问题。您应该为您的网络服务使用 mock 并使用预期的参数对其进行存根。调用实际的服务是没有意义的。单元测试是最快的测试。私有方法是黑盒的一部分,你不应该关心它的内部结构。测试公共接口但不测试私有方法。 如果您将尝试模拟和存根APIService,那么您会注意到如果它是单例则无法做到。您最终会将服务作为依赖项注入 Presenter 以获得更好的可测试性。

    如果要模拟服务并使用存根,则无需使用XCTestExpectation,因为不会有任何异步代码。

    【讨论】:

      【解决方案2】:

      要测试异步方法,您必须使用XCTestExpectation 让您的测试等待异步操作完成。

      这是一个测试异步方法示例

      // Asynchronous test: success fast, failure slow
      func testValidCallToiTunesGetsHTTPStatusCode200() {
          // given
          let url = URL(string: "https://itunes.apple.com/search?media=music&entity=song&term=abba")
          // 1
          let promise = expectation(description: "Status code: 200")
      
          // when
          let dataTask = sessionUnderTest.dataTask(with: url!) { data, response, error in
              // then
              if let error = error {
                  XCTFail("Error: \(error.localizedDescription)")
                  return
              } else if let statusCode = (response as? HTTPURLResponse)?.statusCode {
                  if statusCode == 200 {
                      // 2
                      promise.fulfill()
                  } else {
                      XCTFail("Status code: \(statusCode)")
                  }
              }
          }
          dataTask.resume()
          // 3
          waitForExpectations(timeout: 5, handler: nil)
      }
      

      您可以从 here

      了解更多关于单元测试的信息

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-09-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-28
        • 1970-01-01
        • 1970-01-01
        • 2013-03-14
        相关资源
        最近更新 更多