UIButtonのUnitTestを書く

iOSアプリで、UIButtonが期待通りの挙動になっているかを確認するテストの書き方です。

# 実装

中央にボタンが配置された、簡単なViewControllerがあるとします。

<img width="320" alt="スクリーンショット 2018-05-23 11.45.12.png" src="https://qiita-image-store.s3.amazonaws.com/0/10057/d2897a3c-f6d2-9871-67d6-25a693ac4fbb.png">


```swift
// ViewController.swift

import UIKit

class ViewController: UIViewController {

    let button = UIButton(type: .custom)
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .white
        
        view.addSubview(button)
        
        button.setTitle("タップしてください", for: .normal)
        button.setTitleColor(.blue, for: .normal)
        button.addTarget(self, action: #selector(buttonTouched), for: .touchUpInside)
        
        // UIButtonを画面の中央に貼る
        button.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            button.widthAnchor.constraint(equalToConstant: 240),
            button.heightAnchor.constraint(equalToConstant: 60),
            button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            button.centerYAnchor.constraint(equalTo: view.centerYAnchor)
            ])
    }
    
    @objc func buttonTouched() {
        button.setTitle("タップされました!", for: .normal)
    }
}
```

ボタンをタップすると、タイトルが「タップされました!」に変化します。
このUIButtonのふるまいについて、テストを書いていきます。


# テストコード

## 準備

UnitTest Bundleに `ViewControllerTests.swift` というファイルを追加して、ここにテストを追加していきます。

まず、`@testable import ButtonTestSample` を宣言します。
これにより UnitTest から実装のコードを参照できるようになり、上記で準備して ViewController にアクセスできるようになります。

```swift
// ViewControllerTests.swift

import XCTest
@testable import ButtonTestSample

class ViewControllerTests: XCTestCase { ... }
```

## UIButtonが表示されていることを確認するテスト

インスタンスが生成されていること、addSubviewされていることを確認します。

```swift
class ViewControllerTests: XCTestCase {

    func test_ボタンが表示されること() {
        let vc = ViewController()
        
        XCTAssertNotNil(vc.button)
        XCTAssertTrue(vc.view.subviews.contains(vc.button))
    }
}
```

## UIButtonのタイトルを確認するテスト

タイトルが「タップしてください」になっていることを確認します。


```swift
class ViewControllerTests: XCTestCase {
    // ...

    func test_ボタンのタイトルが期待通りであること() {
        let vc = ViewController()
        
        // ボタンのタイトルの設定はviewDidLoadで行なっています
        // テストでは何も記述がなければ画面が表示されないため、ここでは明示的に呼び出します
        vc.viewDidLoad()
        
        XCTAssertEqual(vc.button.title(for: .normal), "タップしてください")
    }
}
```

テスト名は `test` から始まっていれば自由に名付けられます。
最近は意味が分かりやすいよう、テスト名を日本語にしています。

# タップした際の挙動のテスト

ボタンをタップするとタイトルが変更されることを確認します。

```swift
class ViewControllerTests: XCTestCase {
    // ...
    
    func test_ボタンをタップするとタイトルが変更されること() {
        let vc = ViewController()
        vc.viewDidLoad()
        
        vc.button.sendActions(for: .touchUpInside)
        
        XCTAssertEqual(vc.button.title(for: .normal), "タップされました!")
    }
}
```

ボタンタップのイベントを発生させるのには、`sendActions(for:)`メソッドを使います。
引数に発生させたいイベント（`.touchUpInside`や`.valueChanged`など）を指定します。

# まとめ

UIButton をテストするユニットテストの書き方をいくつか紹介しました。

サンプルコードはこちらに貼っておきます。

* [himaratsu/ButtonTestSample - GitHub](https://github.com/himaratsu/ButtonTestSample)


# 関連

* [UITableViewのUnitTestを書く](https://qiita.com/himara2/items/97613f0b2ff50a356cfc)