連載
» 2014年04月04日 18時00分 公開

Kiwi+CocoaPodsで始めるiOSアプリの振る舞いテスト入門iOSアプリ開発でもCI/継続的デリバリしようぜ(2)(2/4 ページ)

[諏訪悠紀,アンダースコア]

Kiwiでテストケースを書いてみよう

テスト対象のクラスを作成する

 Kiwiの導入が終わったところで、いよいよテストケースを書いてみましょう。まずはテスト対象となる「Team」クラスを作成します。NSObject型を継承したシンプルなクラスにします。

図3 Teamクラスの作成

 ファイルの作成ダイアログでは「Targets」というクラスを追加するターゲットを指定する箇所があります。ここでテスト用のターゲットである「KiwiSampleTests」にチェックマークを付けるようにしてください。

図4 Targetsの設定

 作成したTeamクラスは下記のように実装してください。nameプロパティを持ち、このnameプロパティを初期化時にセットできる「teamWithName:」というコンビニエンスコンストラクターを持ったシンプルなモデルクラスです。このクラスの振る舞いをテストしたいと思います。

#import <Foundation/Foundation.h>
@interface Team : NSObject
+ (instancetype)teamWithName:(NSString*)name;
@property (nonatomic, assign) NSString *name;
@end
Team.h
#import "Team.h"
@implementation Team
+ (instancetype)teamWithName:(NSString*)aName;
{
    Team *team = [[self alloc] init];
    team.name = aName;
    return team;
}
@end
Team.m

テスト用のクラスを作成する

 事前の準備が終わったところで、次にテスト用のクラスを作成しましょう。クラス作成時のテンプレートは「Objective-C test case class」を選択してください。

図5 テンプレートの選択

 クラス名は「TeamSpec」とします。親クラスはデフォルトで指定された「XCTestCase」としていますが、後で書き換えるので何でも構いません。

図6 TeamSpecクラスの作成

書き方の基本を理解しよう

 ファイルが作成できたら、ソースコードを下記のように書き換えてください。

#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.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。