如何测试UIAlertController

7

我正在测试一个显示UIAlertController的函数,但是测试一直失败。这是函数的样子:

func presentBuyingErrorDialogue() {
  let alert = UIAlertController(
    title: "Warning",
    message: "Error purchasing item, please retry this action. If that doesn't help, try restarting or reinstalling the app.",
    preferredStyle: .alert
  )
  let okButton = UIAlertAction(title: "OK", style: .default)
  alert.addAction(okButton)
  self.present(alert, animated: true, completion: nil)
}

因为这个函数在一个叫做ShopViewController的类里,我认为正确的测试方式应该是调用函数shopViewController.presentBuyingErrorDiaologue(),然后使用XCTAssertTrue(shopViewController.presentedViewController is UIAlertController)。然而,当我运行测试时,断言语句失败了。那么正确的测试UIAlertController是否是当前显示的视图的方法是什么?


在你的测试中,尝试执行print(UIApplication.shared.keyWindow?.rootViewController),它显示了什么? - mugx
下面的回答对你有帮助吗? - mugx
非常感谢您迄今为止的帮助!但是我不得不将self.present更改为UIApplication.shared.keyWindow?.rootViewController?.present,有没有一种方法可以在不更改self.present的情况下测试UIController? - Erika
这是用于单元测试还是UI测试? - Jon Reid
@JonReid 一个单元测试 - Erika
显示剩余2条评论
3个回答

7

在测试视图可见性前,你应该等待UIAlertController完全呈现,因此您可以尝试按照以下方式更改测试:

import XCTest

class UIAlertControllerTests: XCTestCase {

    func presentBuyingErrorDialogue() {
      let alert = UIAlertController(title: "Warning", message: "Error purchasing item, please retry this action. If that doesn't help, try restarting or reinstalling the app.", preferredStyle: .alert)
      let okButton = UIAlertAction(title: "OK", style: .default)
      alert.addAction(okButton)
      UIApplication.shared.keyWindow?.rootViewController?.present(alert, animated: true, completion: nil)
    }

    func testPresentBuyingErrorDialogue() {
      self.presentBuyingErrorDialogue()
      let expectation = XCTestExpectation(description: "testExample")
      DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: {
        XCTAssertTrue(UIApplication.shared.keyWindow?.rootViewController?.presentedViewController is UIAlertController)
        expectation.fulfill()
      })
      wait(for: [expectation], timeout: 1.5)
   }
}

您可以将UIApplication.shared.keyWindow?.rootViewController替换为您的ShopViewController

7
  1. ViewControllerPresentationSpy添加到您的测试目标中
  2. import ViewControllerPresentationSpy
  3. 在您的测试调用shopViewController.presentBuyingErrorDialogue()之前实例化AlertVerifier

然后调用其verify方法:

alertVerifier.verify(
    title: "Warning",
    message: "Error purchasing item, please retry this action. If that doesn't help, try restarting or reinstalling the app.",
    animated: true,
    presentingViewController: shopViewController,
    actions: [
        .default("OK"),
    ]
)

这里检查的内容有:

  • 动画展示了一个警告。
  • 呈现视图控制器为shopViewController
  • 警告标题。
  • 警告消息。
  • 首选样式为默认的.alert
  • 每个操作的标题和样式。

除了捕获值之外,AlertVerifier还让您轻松执行警报按钮的操作:

func test_alertOKButton() throws {
    shopViewController.presentBuyingErrorDiaologue()

    try alertVerifier.executeAction(forButton: "OK")

    // Test the results here
}

这些测试不需要等待预期结果,因此非常快速。


1
您可以使用present方法的completion参数,在弹出警报时获取回调,从而了解警报是否已显示。(请注意,这种方法更多地是关于断言正确的操作已执行,而不是正确的视图控制器类型已显示)。
为了使其起作用,您将不得不向您的presentBuyingErrorDialogue方法添加completion参数,但您可以将其默认值设置为nil,以便它不会在非测试代码中干扰您。(当然,当警报出现时,您也可以在应用程序代码中使用它,例如启动背景动画。)
以下是已修改的视图控制器代码:
class ShopViewController: UIViewController {
  func presentBuyingErrorDialogue(completion: (() -> ())? = nil) {
    let alert = UIAlertController(title: "Warning", message: "...", preferredStyle: .alert)
    let okButton = UIAlertAction(title: "OK", style: .default)
    alert.addAction(okButton)
    self.present(alert, animated: true, completion: completion)
  }
}

这是一个简单测试的样例(不考虑对rootViewController进行任何清理):
class ShopViewControllerTests: XCTestCase {
  func testErrorAlert() {
    let vc = ShopViewController()
    UIApplication.shared.keyWindow?.rootViewController = vc
    let exp = expectation(description: "shows alert")
    vc.presentBuyingErrorDialogue {
      exp.fulfill()
    }
    waitForExpectations(timeout: 1)
  }
}

在应用程序代码中,您仍然可以像以前一样使用该方法,无需提供回调块:
let vc = ShopViewController()
vc.presentBuyingErrorDialogue()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接