60分で始めるiOSアプリのUI自動テスト

iOSのアプリケーションではモデル周りのテストと同じぐらいUI周りのテストが重要な気がするのですが、画面のテストってちょっと面倒ですよね。その上Xcode標準のテストフレームワークでは画面遷移などのテストができません。そこで、統合テスト用のテストフレームワークを使う必要がでてきます。

選択肢はいくつかありますが、使い方がシンプルで導入も容易なKIF Frameworkを紹介します。

KIF Framework

kif-framework/KIF · GitHub

KIFは決済サービスSquareが自社アプリケーションの統合テストのために開発したフレームワークだそうです。KIFを使ったテストではボタンをタップして画面遷移したり、画面遷移した先のUIの存在を確認したりといったことを自動でテストできます。

実はiOSのボタンなどの要素にはアクセシビリティのためのアクセシビリティラベルという名前を付けることができるのですが、KIFではこのラベルを頼りにボタンやその他の要素を特定しています。

動画で見ると自動でアプリを操作している様子がよくわかります。

KIFの導入はgithubのREADMEが詳しいのでここでは割愛しますが、CocoaPodsを使ったインストールが可能なのでそちらを強くおすすめします。

CocoaPodsの導入がまだの人はこちら。

CocoaPods.org - The Dependency Manager for Objective C.

KIFの使い方

まずは簡単な例を用いて使い方を紹介します。

storyboardでこんな感じの画面遷移を持ったアプリを作っておきます。赤文字はそれぞれの要素に付けたアクセシビリティラベル。

f:id:cflat-inc:20131211123854p:plain

アクセシビリティラベルはインスペクタから付けることができます。

f:id:cflat-inc:20131211123903p:plain

この画面遷移をテストするためのコードは例えば次のような感じになります。

#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のテストを書き始められるという点が良さそうです。

Test-Driven iOS Development (Developer's Library)

Test-Driven iOS Development (Developer's Library)

  • 作者: Graham Lee
  • 出版社/メーカー: Addison-Wesley Professional
  • 発売日: 2012/04/09
  • メディア: ペーパーバック
  • 購入: 1人 クリック: 19回
  • この商品を含むブログを見る