【问题标题】:How to test UIAlertController如何测试 UIAlertController
【发布时间】:2018-06-23 03:12:01
【问题描述】:

我正在测试一个提供 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),它说了什么?
  • 这是我打印时得到的:可选(
  • 下面我的回答对你有帮助吗?
  • 是的,非常感谢您到目前为止的帮助!但是我必须将 self.present 更改为 UIApplication.shared.keyWindow?.rootViewController?.present,有没有一种方法可以在不更改 self.present 的情况下测试 UIController?
  • 是的,因为我没有你的代码,所以我直接在测试中包含了presentBuyingErrorDialogue。在您的测试用例中,您应该确保您的ShopViewController 可见,然后从单元测试(例如testPresentBuyingErrorDialogue)中使用XCTestExpectation 机制调用正确的presentBuyingErrorDialogue

标签: ios swift uialertcontroller xctest


【解决方案1】:
  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
}

测试不需要任何等待预期,因此速度非常快。

【讨论】:

    【解决方案2】:

    在测试其可见性之前,您应该等待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

    【讨论】:

      【解决方案3】:

      您可以使用present方法的completion参数在出现警报时获取回调,从而判断是否显示警报。 (请注意,这种方法更多地是关于断言执行了正确的操作,而不是显示了正确的视图控制器类型

      为此,您必须将completion 参数添加到您的presentBuyingErrorDialogue 方法,但您可以给它一个默认值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()
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-29
        • 2015-07-16
        • 2016-05-06
        • 1970-01-01
        相关资源
        最近更新 更多