Bluepillを使ってiOS自動テストの並列化

2017年1月21日に複数のiOSシミュレーターを使って自動テストを実行することが可能なツール「[Bluepill](https://github.com/linkedin/bluepill)」がLinkedInにより公開されました。

本稿では、そのBluepillの使い方についての説明を明記します。

## はじめに
1つのマシンでiOSシミュレーターを複数起動したいという思いを持っている人は少なからずいるかと思います。

Bluepillに限らず、複数のiOSシミュレーターを起動できるツールは存在します。
どちらもBluepillがinspireされたツールですが、本稿では詳細については記載しません。

 - [FBSimulatorControl
](https://github.com/facebook/FBSimulatorControl)
 - [pxctest](https://github.com/plu/pxctest)


※上記についての説明がQiita(2017/3/16現在)とかにほぼ無いので、いつか書ければ良いなとは思っています。


### Bluepillの特長
Bluepillは複数のiOSシミュレーターを起動するだけでなく、失敗したテストの許容リトライ数やスタックしたテストの待機時間など色々と設定することができます。

テストケースを複数のiOSシミュレーターで分割して実行してくれます。
シミュレーターが1であれば当然1つで全てのテストケースをおこないますが、複数のシミュレーターを起動すれば分割してテストをおこなってくれます。

## 前提条件
以下の使い方については、KIFやEarlGreyで書いたUIテストのコードがある前提です。

### 補足
Bluepillの最新版ではXCUITestにも対応しているとのことですが、releasesには対応したバージョンがまだありません(2017/3/16現在)。

もし利用したい場合は、自身でビルドしたのを利用することになります。
Bluepillのビルド方法については、READMEに記載されています。


## 事前準備

### Bluepillの用意
[本ページ](https://github.com/linkedin/bluepill/releases)のDownloadsからzipをDLし解凍します。

解凍すると以下の2つのバイナリファイルがあります。
これをBluepillを利用したいプロジェクトのトップにおいておきます。

 - bluepill
 - bp


### build-for-testingをおこなう
次に、テストコードをcompileします。
これによりappファイル(など)が生成されます。

方法については、「Xcode」「xcodebuildコマンド」「Fastlane」の3種類を以下に記載します。
※私は基本的にFastlaneを利用しています。


#### Xcode
Xcodeで作成する場合は、対象となるschemeを選択しメニューバーから「Build For」を選び「Testing」を選択します。
![スクリーンショット 2017-03-11 13.32.16.png](https://qiita-image-store.s3.amazonaws.com/0/37642/4d8c0a02-e9ed-f3ba-d47e-4ec776c09583.png)


作成されたものはXcodeから「Products」から対象となるものを選びメニューを表示させ「Show in Finder」を選択すれば見ることができます。
![スクリーンショット 2017-03-11 13.32.40.png](https://qiita-image-store.s3.amazonaws.com/0/37642/ad837940-4b09-a2d7-aa79-633bacef14d1.png)


#### xcodebuildコマンド
derivedDataPathで指定したディレクトリに成果物ができます。

```
xcodebuild build-for-testing –workspace <path> -scheme <name> -destination <specifier> -derivedDataPath <path>

```


#### Fastlane
derivedDataPathで指定したディレクトリに成果物ができます。

```
xcodebuild(
	workspace: '対象のworkspace',
	scheme: ‘テストのscheme',
	destination: 'platform=iOS Simulator,name=iPhone 6s,OS=latest',
	derivedDataPath: ‘保存先',
	xcargs: "build-for-testing"
)

```


## Bluepillの実行
ここまでくればあとは実行するだけになります。

### コマンドラインからオプション指定して実行
```
./bluepill -a ./Sample.app -s ./SampleAppTestScheme.xcscheme -o ./output/
```

 - aオプション
    - 上記事前準備のbuild-for-testingで作成されたappファイルになります
 - sオプション
    - 実行対象のschemeのパス
    - 例) ./sample.xcodeproj/xcshareddata/xcschemes/sampleUITest.xcscheme
 - oオプション
    - 実行結果の出力先
    - デフォルトだとJUnit形式のテスト結果が出力されます

### コマンドラインから設定ファイルを指定して実行
```
./bluepill -c config.json
```

 - cオプション
   - 設定ファイルのパス

設定ファイルの例

```:config.json
{
   "app": ". /Sample.app",
   "scheme-path": "./SampleAppTestScheme.xcscheme",
   "output-dir": "./output/",
   "device": "iPhone 5s",
   "num-sims": 2
}
```


### オプション
オプションの量は多いので一部をピックアップして以下に記載します。
詳細は[リンク先](https://github.com/linkedin/bluepill#flags)を見るのが良いかと思います。

#### 必須
以下の3種類は必ず必要です。

|configの場合|コマンドラインの場合|内容|
|:----------|:---------------|:---|
|app        |-a              |実行対象となるapp|
|output-dir |-o              |結果の出力先(ログファイル含む)|
|scheme-path|-s              |テストを実行する対象となるscheme|


#### 任意

|configの場合|コマンドラインの場合|内容                      |デフォルト値|
|:-----------|:---------------|:------------------------|:----|
|num-sims    |-n              |シミュレーターの起動数       |4   |
|test-timeout|-T              |テストのタイムアウト時間(sec)|300s|
|headless    |-H              |ヘッドレスにするかどうか     |off |

当然ですが、シミュレーターの起動できる数は利用しているマシンのスペックにも依存します。
私のMacBook Pro(Retina, 15-inch, Mid 2015)/メモリ16Gでは10を指定したらテストまで到達しませんでした。

## Bluepillのテスト実行結果
上記を元に実行すると指定されたシミュレーターが起動し、以下の順番で実行されます。

 - 1) Create Simulator
 - 2) Started Simulator
 - 3) Install Appliication
 - 4) Launch Application
 - 5) Tests started
 - 6) Tests Completed
 - 7) Delete Simulator

実際にテストが実行されるまでの間に、色々とおこなわれるので、テストケース数分のシミュレーターを用いるのが一番はやいとは限らない点に注意しシミュレーターの数を決めるのが良いです。


#### テスト結果の例
テストの結果は指定した箇所に以下のような構成で出力されます。
以下の場合だとシミュレーター数を4つ指定しています。

```
 - ./output
   - /1
     - 1-SampleAppTestScheme-results.txt
     - 1-SampleAppTestScheme-timings.json
     - 1-simulator.log
     - SampleAppTestScheme-status.txt
     - TEST-SampleAppTestScheme-results.xml
   - /2
     - 1と同様
   - /3
     - 1と同様
   - /4
     - 1と同様
   - TEST-FinalReport.xml
```

「TEST-FinalReport.xml」には全てのテスト結果が登録されています。
Jenkinsなどで利用する場合は、「TEST-FinalReport.xml」をテスト結果として集約すれば良いです。


## 終わりに
まだBluepillはissueが色々とあるのですが、思ったよりさくっと使えるので使ってみてほしいです。

テストケースが少ない場合において効果があるか？という疑問もあるかと思いますが、許容リトライ数などiOSのシミュレーターの不安定さへの対策が多少なりとも出来るので、利用するのはありだと思います。

## 参考資料
 - https://github.com/linkedin/bluepill
 - [Bluepill: LinkedInによる大規模iOS UI テストのためのオープンソースツール](https://www.infoq.com/jp/news/2017/01/linkedin-bluepill-ios-testing)
 - [Advanced Testing and Continuous Integration - Apple](http://devstreaming.apple.com/videos/wwdc/2016/409jh83sf1h8dqrt00q/409/409_advanced_testing_and_continuous_integration.pdf)