[Swift] UIAlertViewControllerもモックでテストする

# はじめに
皆様、ユニットテストされていますか？
Model周りはテストしやすいですが、ViewController周りはテストしずらいですよね。

今日は、モックを使って、UIAlertViewController(Alert)をテストする方法をご紹介します。

# ユニットテストの種類
| テストの種類 | 説明 | 
| --- | --- |  
| スタブ | メソッドの戻り値にダミーの値を返すこと |
| モック | メソッドが呼ばれているか、プロパティに値がセットされているか確認すること |
| パーシャルモック | 既存のクラスのうち一部のメソッドをモック化すること|

# プロトコルを利用して、モック化する
UIAlertViewControllerのAlertを例に説明します。

## プロトコル

```:DialogPresenter.swift
import UIKit

protocol DialogPresenter {
    func present(title: String, message: String?, onOK: (Void -> Void),
                 onTopOf presenter: UIViewController)
}
```

## OKとCancelボタン付きのアラート

```:OKCancelDialogPresenter.swift
import UIKit

class OKCancelDialogPresenter: DialogPresenter {

    func present(title: String, message: String?, onOK: (Void -> Void),
                 onTopOf presentingViewController: UIViewController) {
        
        let alert = UIAlertController(title: title, message: message, preferredStyle: .Alert)

        let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
        alert.addAction(cancelAction)

        let okAction = UIAlertAction(title: "OK", style: .Default) { _ in onOK() }
        alert.addAction(okAction)

        presentingViewController.presentViewController(alert, animated: true, completion: nil)
    }
}
```

## ViewControllerから呼ぶ
ボタンが押下されたら、ダイアログを表示する

```:ViewController.swift
    @IBAction func didTapButton(sender: UIButton) {

        OKCancelDialogPresenter().present("タイトル",
                                          message: "メッセージ",
                                      onOK: { (Void) in
                                        print(#function)
            },
                                      onTopOf: self)
    }
```

## モックを作る
メソッドが呼ばれたか、プロパティに正しく値がセットされているか確認する

```:MocDialogPresenter.swift
import UIKit

class MocDialogPresenter: DialogPresenter {

    var present_wasCalled = false
    var present_wasCalled_withArgs: (title: String, message: String?,
        onOK: (Void -> Void), presentingVC: UIViewController)? = nil

    func present(title: String, message: String?, onOK: (Void -> Void),
                 onTopOf presenter: UIViewController) {

        present_wasCalled = true
        present_wasCalled_withArgs = (title: title, message: message, onOK: onOK, presentingVC: presenter)
    }
}
```

## ユニットテストする

```:DialogTest.swift
import XCTest

class DialogTest: XCTestCase {

    override func setUp() {
        super.setUp()
    }
    
    override func tearDown() {
        super.tearDown()
    }

    func testOKCancelDialog() {

        let dialog = MocDialogPresenter()

        dialog.present("タイトル",
                       message: "メッセージ",
                       onOK: { (Void) in },
                       onTopOf: UIViewController())

        XCTAssertTrue(dialog.present_wasCalled)
        XCTAssertEqual("タイトル", dialog.present_wasCalled_withArgs?.title)
        XCTAssertEqual("メッセージ", dialog.present_wasCalled_withArgs?.message)
        XCTAssertNotNil(dialog.present_wasCalled_withArgs?.onOK)
        XCTAssertNotNil(dialog.present_wasCalled_withArgs?.presentingVC)
    }
}
```

# まとめ
プロトコルを利用してモック化する方法をご紹介しました。
ViewControllerからPresenterに切り出せる処理は、
ユニットテストしていきたいと思います。

# 参考記事
下記の記事を参考に纏めさせて頂きました。
大変勉強になりました。

https://realm.io/jp/news/rachel-bobbins-testing-view-controllers-quick/
https://realm.io/jp/news/tryswift-veronica-ray-real-world-mocking-swift/