Kiwi+CocoaPodsで始めるiOSアプリの振る舞いテスト入門:iOSアプリ開発でもCI/継続的デリバリしようぜ(2)(2/4 ページ)
現代の開発現場において欠かせないCI/継続的デリバリを、iOSアプリ開発に適用するためのツールやノウハウを解説する連載。今回は、iOSアプリの機能の振る舞いをテストするテスティングフレームワークの特長とインストールの仕方、主な使い方を解説します。
Kiwiでテストケースを書いてみよう
テスト対象のクラスを作成する
Kiwiの導入が終わったところで、いよいよテストケースを書いてみましょう。まずはテスト対象となる「Team」クラスを作成します。NSObject型を継承したシンプルなクラスにします。
ファイルの作成ダイアログでは「Targets」というクラスを追加するターゲットを指定する箇所があります。ここでテスト用のターゲットである「KiwiSampleTests」にチェックマークを付けるようにしてください。
作成したTeamクラスは下記のように実装してください。nameプロパティを持ち、このnameプロパティを初期化時にセットできる「teamWithName:」というコンビニエンスコンストラクターを持ったシンプルなモデルクラスです。このクラスの振る舞いをテストしたいと思います。
#import <Foundation/Foundation.h> @interface Team : NSObject + (instancetype)teamWithName:(NSString*)name; @property (nonatomic, assign) NSString *name; @end
#import "Team.h" @implementation Team + (instancetype)teamWithName:(NSString*)aName; { Team *team = [[self alloc] init]; team.name = aName; return team; } @end
テスト用のクラスを作成する
事前の準備が終わったところで、次にテスト用のクラスを作成しましょう。クラス作成時のテンプレートは「Objective-C test case class」を選択してください。
クラス名は「TeamSpec」とします。親クラスはデフォルトで指定された「XCTestCase」としていますが、後で書き換えるので何でも構いません。
書き方の基本を理解しよう
ファイルが作成できたら、ソースコードを下記のように書き換えてください。
#import "Kiwi.h" #import "Team.h" SPEC_BEGIN(TeamSpec) describe(@"teamWithName:", ^{ context(@"引数がある場合", ^{ it(@"nameが「テストチーム」であること", ^{ Team *team = [Team teamWithName:@"テストチーム"]; [[team.name should] equal:@"テストチーム"]; }); }); }); SPEC_END
これがKiwiのテストケースの基本的な構成です。どのような構成になっているのか順番に確認していきましょう。
まずKiwiのテストケースはSPEC_BEGINマクロで始め、SPEC_ENDマクロで終わらせます。SPEC_BEGINマクロでは、KiwiのKWSpecクラスを継承した@interfaceや@implementationを実装しており、SPEC_ENDマクロでは@endだけが実装されています。
SPEC_BEGINマクロの引数には、対象とするクラスのテストクラス名を指定します。テストクラス名になるだけですので、自由な名前で構いません。
次に、テストケースを見ていきましょう。Kiwiのテストケースは、describeメソッド、contextメソッド、itメソッドなどで階層構造を作って記述していきます。
これらのメソッドは第1引数に振る舞いの説明文、第2引数にブロック構文を渡します。振る舞いの説明文はテスト結果の出力で使用され、ブロック構文の中には実行したいテストの処理を記述していきます。
describeメソッドはテストする対象を表し、contextメソッドはテストするときの状況を表し、itメソッドはテストケースの一例を表します。つまり上記の例は、「teamWithName:」メソッドを対象とした、「引数がある場合」という条件で、「nameに『テストチーム』を持っていること」という一例のテストケースです。
itメソッドを複数記述
ここで、もう少しテストケースを加えてみましょう。先ほどのソースコードを下記のように書き換えてください。
#import "Kiwi.h" #import "Team.h" SPEC_BEGIN(TeamSpec) describe(@"teamWithName:", ^{ context(@"引数がある場合", ^{ it(@"nameが「テストチーム」であること", ^{ Team *team = [Team teamWithName:@"テストチーム"]; [[team.name should] equal:@"テストチーム"]; }); it(@"nameが空ではないこと", ^{ Team *team = [Team teamWithName:@"テストチーム"]; [[team.name shouldNot] beNil]; }); }); context(@"引数がない場合", ^{ it(@"nameが空であること", ^{ Team *team = [Team teamWithName:nil]; [[team.name should] beNil]; }); }); }); SPEC_END
「引数がある場合」のcontextメソッドの中に「nameが空ではないこと」というitメソッド、「引数がない場合」というcontextメソッド、さらに「nameが空であること」というitメソッドを追加しました。このように、describeメソッド、contextメソッド、itメソッドは同じ階層内に複数記述できるので、さまざまな条件を分かりやすい形で記述できます。
対象となるクラスのどのような振る舞いをテストしたいかよく考えよう
今回の例は、一般的なモデルクラスを対象としたテストケースでしたが、describeメソッド、contextメソッド、itメソッドの構成は対象とするクラスの振る舞いによって異なってきます。テストケースを作成するときは、対象となるクラスのどのような振る舞いをテストしたいかよく考え、それに沿って構成するようにしましょう。
Copyright © ITmedia, Inc. All Rights Reserved.