SwiftでUIAlertControllerをテストする方法

4943 ワード

最近、Objective-Cでcontrol swizzlingを使用してUIAlertControllerをテストする記事を読みました.このような文章はいつもcontrol swizzlingを使わなくても同じものをテストできる方法を探しています.swizzlingは開発者の非常に強力なツールであることは知っていますが、個人的にはできるだけ避けることができます.実際、最近の6年間、私は1つのアプリケーションでswizzlingを使っただけです.だから私たちは今swizzlingを使わずにテストを実現できると信じています.
では、問題が発生しました.どのようにしてSwiftでswizzlingを使用しないでUIalertControllerをテストしますか?
まず、テストするコードから始めましょう.Storyboardにボタンを追加しました.(私がStoryboardを使っているのは、コードでインタフェースを書きたくない仲間にもっと直感的に感じさせるためです)このボタンを押すと、タイトル、メッセージの内容、そしてOKとキャンセル(Cancel)の2つのボタンが表示されます.
次はこのコードです.

import UIKit
class ViewController: UIViewController {
 var actionString: String?
 @IBAction func showAlert(sender: UIButton) {
  let alertViewController = UIAlertController(title: "Test Title", message: "Message", preferredStyle: .Alert)
  let okAction = UIAlertAction(title: "OK", style: .Default) { (action) -> Void in
   self.actionString = "OK"
  }
  let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (action) -> Void in
   self.actionString = "Cancel"
  }
  alertViewController.addAction(cancelAction)
  alertViewController.addAction(okAction)
  presentViewController(alertViewController, animated: true, completion: nil)
 }
}

なお、この例では、弾窓動作は具体的な操作を行わず、ユニットテストを検証できることを示しているだけである.
簡単なテストを始めましょう.この弾窓コントローラのタイトルとメッセージの内容をテストします.
テストのコードは次のとおりです.

import XCTest
@testable import TestingAlertExperiment
class TestingAlertExperimentTests: XCTestCase {
 var sut: ViewController!
 override func setUp() {
  super.setUp()
  sut = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() as! ViewController
  UIApplication.sharedApplication().keyWindow?.rootViewController = sut
 }
 override func tearDown() {
  // Put teardown code here. This method is called after the invocation of each test method in the class.
  super.tearDown()
 }
}
```

sutをルートビューコントローラに設定する必要があります.そうしないと、ビューコントローラはこのポップアップビューコントローラをポップアップできません.
UIalertControllerテストタイトルを追加するコードは次のとおりです.

```Swift
func testAlert_HasTitle() {
 sut.showAlert(UIButton())
 XCTAssertTrue(sut.presentedViewController is UIAlertController)
 XCTAssertEqual(sut.presentedViewController?.title, "Test Title")
}
``` 

これは簡単です.UIAlertControllerのキャンセルボタンをテストします.ここで問題があります.弾窓動作の閉パッケージを取得できません.そのため、このhandlerを格納し、テストで呼び出すために、弾窓動作が予想通りかどうかを確認するために、弾窓動作をシミュレートする必要があります.テスト・インスタンスに次のクラスを追加します.

```Swift
class MockAlertAction : UIAlertAction {
 typealias Handler = ((UIAlertAction) -> Void)
 var handler: Handler?
 var mockTitle: String?
 var mockStyle: UIAlertActionStyle
 convenience init(title: String?, style: UIAlertActionStyle, handler: ((UIAlertAction) -> Void)?) {
  self.init()
  mockTitle = title
  mockStyle = style
  self.handler = handler
 }
 override init() {
  mockStyle = .Default
  super.init()
 }
}

このシミュレーションクラスの主な仕事はhandlerブロックをキャプチャして後で使用することである.このシミュレーションのクラスを実装コードに挿入する必要があります.ビューコントローラのコードを次のように変更します.

import UIKit
class ViewController: UIViewController {
 var Action = UIAlertAction.self
 var actionString: String?
 @IBAction func showAlert(sender: UIButton) {
  let alertViewController = UIAlertController(title: "Test Title", message: "Message", preferredStyle: .Alert)
  let okAction = Action.init(title: "OK", style: .Default) { (action) -> Void in
   self.actionString = "OK"
  }
  let cancelAction = Action.init(title: "Cancel", style: .Cancel) { (action) -> Void in
   self.actionString = "Cancel"
  }
  alertViewController.addAction(cancelAction)
  alertViewController.addAction(okAction)
  presentViewController(alertViewController, animated: true, completion: nil)
 }
}

```

クラス変数`Action`を追加し、`UIalertActionに設定した.self`.この変数は弾窓動作を初期化する際に使用します.これにより、テスト時に書き換えることができます.このように:

```Swift
func testAlert_FirstActionStoresCancel() {
 sut.Action = MockAlertAction.self
 sut.showAlert(UIButton())
 let alertController = sut.presentedViewController as! UIAlertController
 let action = alertController.actions.first as! MockAlertAction
 action.handler!(action)
 XCTAssertEqual(sut.actionString, "Cancel")
}

まず私たちはこの弾窓動作を挿入しました.その後、コードポップアップウィンドウビューコントローラを呼び出します.レンダリングされたビューコントローラからキャンセル動作を取得し,キャプチャされたhandlerブロックの呼び出しに成功した.最後のステップは、現在の動作が私たちが予想していたのと同じかどうかを断言することです.
このように、swizzlingを使用せずにUIalertView Controlをテストする方法です.
以上は、SwiftでUIAlertControllerをテストする方法についてですが、皆さんに役に立つと思います.