60分で始めるiOSアプリのUI自動テスト
iOSのアプリケーションではモデル周りのテストと同じぐらいUI周りのテストが重要な気がするのですが、画面のテストってちょっと面倒ですよね。その上Xcode標準のテストフレームワークでは画面遷移などのテストができません。そこで、統合テスト用のテストフレームワークを使う必要がでてきます。
選択肢はいくつかありますが、使い方がシンプルで導入も容易なKIF Frameworkを紹介します。
KIF Framework
GitHub - kif-framework/KIF: Keep It Functional - An iOS Functional Testing Framework
KIFは決済サービスSquareが自社アプリケーションの統合テストのために開発したフレームワークだそうです。KIFを使ったテストではボタンをタップして画面遷移したり、画面遷移した先のUIの存在を確認したりといったことを自動でテストできます。
実はiOSのボタンなどの要素にはアクセシビリティのためのアクセシビリティラベルという名前を付けることができるのですが、KIFではこのラベルを頼りにボタンやその他の要素を特定しています。
動画で見ると自動でアプリを操作している様子がよくわかります。
KIFの導入はgithubのREADMEが詳しいのでここでは割愛しますが、CocoaPodsを使ったインストールが可能なのでそちらを強くおすすめします。
CocoaPodsの導入がまだの人はこちら。
KIFの使い方
まずは簡単な例を用いて使い方を紹介します。
storyboardでこんな感じの画面遷移を持ったアプリを作っておきます。赤文字はそれぞれの要素に付けたアクセシビリティラベル。
アクセシビリティラベルはインスペクタから付けることができます。
この画面遷移をテストするためのコードは例えば次のような感じになります。
#import <KIF/KIF.h> @interface NavigationTests : KIFTestCase @end @implementation NavigationTests - (void)test { // Label1が現れるのを待つ [tester waitForViewWithAccessibilityLabel:@"Label1"]; // NextPageButtonをタップする [tester tapViewWithAccessibilityLabel:@"NextPageButton"]; // SecondPageLabelが現れるのを待つ [tester waitForViewWithAccessibilityLabel:@"SecondPageLabel"]; // ナビゲーションのBackをタップする [tester tapViewWithAccessibilityLabel:@"Back"]; // Label1が現れるのを待つ [tester waitForViewWithAccessibilityLabel:@"Label1"]; } @end
何も起こらなければテストは無事成功です。
KIFの使い方応用編
テストの前後に特定の処理を入れたい場合
beforeEach, beforeAll, afterEach, afterAllなどのメソッドを定義すれば良いです。
beforeEach | 各テストケースの前に呼ばれる |
beforeAll | 最初に1回呼ばれる |
afterEach | 各テストケース終了後に呼ばれる |
afterAll | 全てのテスト終了後に呼ばれる |
例えばこんな感じで書きます。
@implementation NavigationTests - (void)beforeEach { // do something... } - (void)test { // ... } @end
要素の有無の確認
先の例ではLabel1があることを確認するために次のように書いていました。
- (void)test { // Label1が現れるのを待つ [tester waitForViewWithAccessibilityLabel:@"Label1"]; }
同じ画面にLabel2やLabel3もあるので、それらのラベルがあることもテストしたいというケースもあるでしょう。こういう場合はwaitForViewWithAccessibilityLabelを複数並べれば大丈夫。
- (void)test { [tester waitForViewWithAccessibilityLabel:@"Label1"]; [tester waitForViewWithAccessibilityLabel:@"Label2"]; [tester waitForViewWithAccessibilityLabel:@"Label3"]; }
その他のよく使いそうなAPI
- (void)tapScreenAtPoint:(CGPoint)screenPoint;
CGPointで画面上の特定の箇所をタップさせる際に有効です。私の場合、タブバーのボタンをタップさせて画面を切り替えるときに使用しました。UITabBarItemにはstoryboardでAccessibilityLabelをつけられない上、コードでLabelを付けてもKIFが認識してくれないというケースがあったので。
// タップ可能な要素が現れるのを待つ - (UIView *)waitForTappableViewWithAccessibilityLabel:(NSString *)label // 要素が消えるのを待つ - (void)waitForAbsenceOfViewWithAccessibilityLabel:(NSString *)label // 長押し - (void)longPressViewWithAccessibilityLabel:(NSString *)label duration:(NSTimeInterval)duration; // テキスト入力 - (void)enterText:(NSString *)text intoViewWithAccessibilityLabel:(NSString *)label; // スイッチ切替 - (void)setOn:(BOOL)switchIsOn forSwitchWithAccessibilityLabel:(NSString *)label
まとめ
- 導入に時間がかからない
- シンプルに使える(学習コストが低い)
もう少し凝った使い方もできそうですが、それよりも導入が楽で簡単にUIのテストを書き始められるという点が良さそうです。