XCTestのUIテストの結果をイイ感じで見たい

直近で新たに画面を作成する案件があったんですが、もういい加減テスト端末を用意したりたくさんのシミュレーターを起動したりするの面倒ですよね。
僕はこれまで [Lunch](https://github.com/fromkk/Lunch) というライブラリを作成してUIテストから直接画面を指定して起動出来る様にしたり、
[最近アップデートした個人アプリのWebCollector](https://qiita.com/fromkk/items/ae51d04002dbbece179d) ではUIテストの結果をスクリーンショットに保存する様な工夫をしてきました。
ただ、そこで困っていたのが撮影したスクリーンショットを **イイ感じに表示したい** という事でした。

そういう時にパッと思い浮かぶのはFastlane等のツール群ですが、そもそも `snapshot` を利用していないので厳しいのかなと思いました。

## `-resultBundlePath` オプション

`xcodebuild` のオプションに `-resultBundlePath` を設定する事で下記の様なファイル達が作成されます

<img width="375" alt="Screen Shot 2018-04-24 at 20.43.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/2846/705e082a-626a-9532-ec04-f03465233aed.png">

この中にある `TestSummaries.plist` というものを見てみると下記の様になっています。

![Screen Shot 2018-04-24 at 21.02.48.png](https://qiita-image-store.s3.amazonaws.com/0/2846/68151afd-a788-c505-357a-72c0df2bf829.png)

また、`Attachments` フォルダの中にはスクリーンショットが保存されています。

![Screen Shot 2018-04-24 at 21.03.55.png](https://qiita-image-store.s3.amazonaws.com/0/2846/a0a77467-3f14-79a8-c3e2-5d5ced9325a5.png)

`TestSummaries.plist` を奥底まで辿っていくと `ActivitySummaries` がありスクリーンショットを撮影したテストには `Attachments` という配列がいます。
`Attachment` オブジェクトには `Filename` があり、これが先ほどの `Attachments` フォルダの中にあるファイル名と紐づいています。

## `Codable` で `TestSummaries.plist` をパース

JSONのエンコード/デコードに注目されがちなSwift 4から実装されている `Codable` ですが、`PropertyListEncoder` と `PropertyListDecoder` があるのをお忘れではないでしょうか？
下記の様にすればplistファイルを簡単にデコードする事ができます。

```swift
let testSummariesURL = URL(fileURLWithPath: bundlePath).appendingPathComponent("TestSummaries.plist")
let data = try Data(contentsOf: testSummariesURL)
let plistDecoder = PropertyListDecoder()
let testSummaries = try plistDecoder.decode(TestSummaries.self, from: data)
```

デコードするモデルは `TestSummaries.plist` とにらめっこしながら頑張って書き起こします。

```swift
struct TestSummaries: Codable, Equatable {
    
    let formatVersion: String
    
    let testableSummaries: [TestableSummary]
    
    private enum CodingKeys: String, CodingKey {
        case formatVersion = "FormatVersion"
        case testableSummaries = "TestableSummaries"
    }
}

struct TestableSummary: Codable, Equatable {
    let diagnosticsDirectory: String
    let projectPath: String
    let targetName: String
    let testName: String
    let testObjectCLass: String
    let tests: [Test]
    
    private enum CodingKeys: String, CodingKey {
        case diagnosticsDirectory = "DiagnosticsDirectory"
        case projectPath = "ProjectPath"
        case targetName = "TargetName"
        case testName = "TestName"
        case testObjectCLass = "TestObjectClass"
        case tests = "Tests"
    }
    
}

struct Test: Codable, Equatable {
    let duration: TimeInterval
    let subTests: [Test]?
    let activitySummaries: [ActicitySummary]?
    let testIdentifier: String
    let testName: String
    let testObjectClass: String
    let testStatus: String?
    let testSummaryGUID: String?
    
    private enum CodingKeys: String, CodingKey {
        case duration = "Duration"
        case subTests = "Subtests"
        case activitySummaries = "ActivitySummaries"
        case testIdentifier = "TestIdentifier"
        case testName = "TestName"
        case testObjectClass = "TestObjectClass"
        case testStatus = "TestStatus"
        case testSummaryGUID = "TestSummaryGUID"
    }
}

.
.
.
```

パースが完了したらあとは欲しい情報をまとめて表示するだけですね！

## Terminalで動作するコマンドラインツールを作ってみた

と、自分で作るのはなかなか大変ですよね。
今回初めてMacのTerminal上で動作するコマンドラインツールを作ってみました。

Githubはこちらです
[fromkk/TestSummaries](https://github.com/fromkk/TestSummaries)

### インストール方法

Homebrewを利用してインストールする場合は下記のコマンドでインストール可能です。

```sh
brew install fromkk/TestSummaries/testsummaries
```

(Homebrew経由でインストールさせる方法は[Swift Package Manager(SwiftPM)で作ったコマンドラインツールをHomebrewに登録する方法](https://qiita.com/mono0926/items/c32c008384df40bf4e41)こちらを参考にさせて頂きました :bow: )

また、Githubからクローンする場合は下記の通りです。

```sh
git clone git@github.com:fromkk/TestSummaries.git
cd ./TestSummaries
make install
```

### 利用方法

利用する場合は `test-summaries` コマンドを利用します

```sh
test-summaries [--resultDirectory <resultDirectory>] | [--bundlePath <bundlePath>] --outputPath <outputPath>
```

オプションは下記の通りです。

オプション名 | 説明
-----------|-----
| --resultDirectory | 複数のテストのスクリーンショットをまとめて表示したい場合に、親ディレクトリのパスを指定します |
| --bundlePath | 1つのテストのスクリーンショットを表示したい場合に、バンドルのパスを指定します |
| --outputPath | 生成したHTMLファイルを保存するパスを指定します |

### 結果

下記の様なHTMLファイルが生成されます :tada: 

![capture.png](https://qiita-image-store.s3.amazonaws.com/0/2846/88f41c78-4ab2-812b-db11-7144c4652802.png)

## まとめ

念願のスクショをイイ感じに見る事が出来る様になりました。
これまでは1枚ずつ見比べる必要があったのが、HTMLを開くだけで各端末や条件のテストの差異が見れる様になったのは大きな前進な気がします。
ただ、コードはかなり急いで作ったのでかなり粗があるかと思います。
不具合や要望などあればコメントやissue、PRを頂ければと思います :bow: 

いいなと思ったら **いいね👍🏻** や [Github](https://github.com/fromkk/TestSummaries) にスター🌟ください！

(テストの為のツールにテストが書かれていないとは何事か...その内書きます😅)