[iOS] KIFを使ってUIテスト


テストの様子

![sample.gif](https://qiita-image-store.s3.amazonaws.com/0/5616/62197dc8-9f99-42dc-8dd3-b464e5701a3f.gif "sample.gif")


UIテストについて最近色々と調べています。
*Appium試したらMobile Safariが消えてうろたえたっていうのはナイショ。*

まだどれも記事を読んだり少し触ったり、ということくらいしかしていませんが、[KIF](https://github.com/kif-framework/KIF)が今のところよさげかなーと思っています。
理由としてはUIテストをすべてObjective-Cで書けるのが大きい。

JavaScriptとかで書けるのもあってそっちもよさそうですが、iOSエンジニア以外でテストを書くことが今のところはなさそうなので、そういう意味では言語を統一しておく、というのがいいかなと。

UIテスト周りについては以下の記事を参考にさせてもらいました。

* [iOSアプリのUIテストツール候補](http://qiita.com/hirayaCM/items/513786631575db8e1fb1)
* [60分で始めるiOSアプリのUI自動テスト](http://cflat-inc.hatenablog.com/entry/2014/01/06/214736)

##サンプルプロジェクト

今回、色々実際に触ってみるにあたって作ったものを[Githubに公開](https://github.com/edom18/KIFSample)しています。


##準備

*【注意】KIFのGithubのREADMEを読むと、UndocumentなAPIを使っているからアプリ内に含めるとリジェクトされるぜ、ってことが書かれています。*

KIFを使うにはCocoaPodsでインストールするか、Githubからソースコードを落としてきて利用するかの2つの方法があります。
自分はCocoaPodsからインストールしました。

Podfileに以下のように設定を書いてインストールします。

```Podfile
target 'Acceptance Tests', :exclusive => true do
  pod 'KIF', '~> 3.0'
end
```

`target`に指定されているのは実際に自分のプロジェクトに追加したtargetを指定します。
（なので事前に作っておく必要があります）

そしてインストールが完了するとworkspaceファイルができているので、Xcodeを再起動してそのファイルを開きます。
これで準備完了です。


##テストを書く
テストは`tester`というマクロが書かれているので、これを元に色々なメソッドを実行してテストを書いていきます。
大まかな流れは、

* 期待するもの（あるいは指定時間）が表示されるのを待つ
* 表示されたビューをタップ、あるいは文字入力

という、ユーザが利用するシナリオを想定しながら、 **表示→アクション→表示→アクション**を繰り返していきます。
なので、比較的ユーザの見ている視点でテストを続けていくことができます。

##サンプル
テストはおおまかに以下のように書いていきます。

```objc
// KIFの読み込みと、KIFTestCaseを継承したクラスを作る

// HogeTestCase.h
#import <KIF/KIF.h>

@interface HogeTestCase : KIFTestCase

@end
```

```objc
// HogeTestCase.m

@implementation HogeTestCase

- (void)beforeEach
{
	NSLog(@"ひとつのテストケースが始まる前に毎回実行される");
}

- (void)afterEach
{
	NSLog(@"ひとつのテストケースが終わる度に実行される");
}

// 頭に`test`を付けてメソッドを実装するとテストケースとして認識される
- (void)testSample
{
	// `hoge`というアクセシビリティラベルのついた要素が表示されるのを待つ
	[tester waitForViewWithAccessibilityLabel:@"hoge"];

	// `hoge`というアクセシビリティラベルがついた要素に指定した文字を入力する
	[tester enterText:@"hoge text" intoViewWithAccessibilityLabel:@"hoge"];

	// `fuga`というアクセシビリティラベルがついた要素をタップする
	[tester tapViewWithAccessibilityLabel:@"fuga"];
}

@end
```

こんな感じで、ビューを待つ、なにかアクション、ビューを待つ、というのを繰り返していきます。
上記の例で言えば、ログイン処理なんかが分かりやすい例でしょうか。（ユーザ名とパスワードを入力したらログインボタンを押す、みたいな）

テストが無事に通るとアプリは終了され、無事に通った旨のログが出力されます。


##使えるメソッド

以下のメソッドは`KIFTestCase`を継承したクラスのインスタンスメソッドとしてオーバーライドします。

| メソッド | 意味 |
|--------|--------|
| beforeEach | 各テストケースごとに開始時に実行される |
| beforeAll | テスト開始時に1回だけ実行される |
| afterEach | 各テストケースごとに終了時に実行される |
| afterAll | テスト終了後に1回だけ実行される |

##主なテスト用メソッド

```objc
// `label`を持った要素が現れるのを待つ
- (UIView *)waitForViewWithAccessibilityLabel:(NSString *)label;

// `screenPoint`で指定した位置をタップする
- (void)tapScreenAtPoint:(CGPoint)screenPoint;

// `label`を持つ、タップ可能な要素が現れるのを待つ
- (UIView *)waitForTappableViewWithAccessibilityLabel:(NSString *)label;

// `label`を持つ、要素が消えるのを待つ
- (void)waitForAbsenceOfViewWithAccessibilityLabel:(NSString *)label;

// `label`を持つ要素を長押し
- (void)longPressViewWithAccessibilityLabel:(NSString *)label duration:(NSTimeInterval)duration;

// `label`を持つ要素にテキスト入力を入力
- (void)enterText:(NSString *)text intoViewWithAccessibilityLabel:(NSString *)label;

// `label`を持つスイッチを切替
- (void)setOn:(BOOL)switchIsOn forSwitchWithAccessibilityLabel:(NSString *)label;
```