[前回]
Cocoaの日々: [iOS] Static Library (5) Frameworkを作成する
ライブラリのテスト
ライブラリは画面が無いのでデバッグがしずらい。テスト目的の専用アプリを用意するのもいいのだが、開発中は単体テストを導入するのが正攻法だろう。SDKには単体テスト用フレームワーク OCUnit が標準で付属するのでこれを使ってみる。これを使うとビルド時にテストケースを実行して問題があればこんな感じで Xcodeのビルド結果画面にエラーを表示してくれる。
手順
1.準備
まず OCUnit検証用に Static Library 開発用のサンプルプロジェクトを新規作成する。
テスト対象としてこんなクラスを用意しておく。
@interface SampleClass : NSObject {
}
- (NSString*)greeting;
@end
@implementation SampleClass
- (NSString*)greeting
{
return @"Hello";
}
@end
この状態でビルドするとライブラリ(*.a)が作成される。
2. Unit Test Bundle
テスト用ターゲットとして Unit Test Bundle を追加する。
名前を "Unit Test" としてみた。
このターゲットの情報を開き「一般」タブの「直接依存関係」へライブラリビルド用のターゲットを追加する。こうするとテスト用ターゲットを実行した時、事前にライブラリのビルドを実行してくれる。
またテストケースを実行するプログラムをビルドするのにライブラリ(*.a)をリンクする必要があるのでこのターゲットへ先ほどビルドしたライブラリファイルを追加する。Products にある *.a ファイルをドラッグ&ドロップで「バイナリをライブラリにリンク」へ追加することができる(メニューから追加しても良い)。
3. テストケースを追加する
新規ファイルとして "Objective-C test case class" を選択する。
追加したテストケースのクラスファイルのターゲットを "Unit Test"にしておく。これをしないとテストケースが実行されない。
テストケースがサンプルとして自動生成されるがこれは削除して良い
4. テストケース実行
まず最初にこんなテストケースを書いてみた。
- (void)testGreeting
{
counter_++;
SampleClass* obj = [[[SampleClass alloc] init] autorelease];
STAssertTrue([[obj greeting] isEqualToString:@"x"],
@"failed");
}
テスト用メソッド名はtestで開始する必要がある。
アクティブターゲットに "Unit Test" を選択してビルドする。
出た。
わかったことなど
テストケース実行が成功したのでいろいろいじってみた。わかったことは次の通り。
STAssert* マクロは可変引数を取る
STAssert*マクロは可変引数で NSLog() の様に追加情報を表示することもできる。こんな感じ。
STAssertTrue([[obj greeting] isEqualToString:@"x"],
@"*%d-%@*", 1, @"A");
なおメッセージに ":" を含めるとそれより前の文字が表示されない。
(例)@"failed: A" => A と表示される
また、STAssertTrue(..., @"%@", self) とすると実行中のメソッド名が表示される。
メンバ変数
メンバ変数を使うことも可能。
@interface SampleClassTest : SenTestCase {
NSInteger counter_;
}
テストケース実行順はメソッド名昇順
テストメソッドを追加してみた。実行順序はメソッド名昇順のようだ。
- (void)testFirst
{
counter_++;
STAssertTrue(NO, @"counter=%d", counter_);
}
テストケース毎にインスタンスが生成される
それぞれのメソッドでアドレスを表示させてみると別の値が表示された。テストメソッド実行毎にインスタンスは新規作成されているのがわかる。
複数のテストケースクラス
これも名前順に実行された。
デバッグ表示できない
NSLog(), fputs("..", stderr) などでテストケースからの出力を見ることができない。
初期化と後始末
setUp/tearDown メソッドを書くとテストケース実行前後に処理を実行させることができる。
-(void) setUp
{
// 初期化処理
counter_ = 100;
:
}
その他
実機ビルドではテストできない。
テストメソッドはヘッダファイルで宣言する必要は無い
備考:テストマクロの種類
SenTestCase.h より
#define STAssertNil(a1, description, ...)
#define STAssertNotNil(a1, description, ...)
#define STAssertTrue(expression, description, ...)
#define STAssertFalse(expression, description, ...)
#define STAssertEqualObjects(a1, a2, description, ...)
#define STAssertEquals(a1, a2, description, ...)
#define STAssertEqualsWithAccuracy(left, right, accuracy, description, ...)
#define STAssertThrows(expression, description, ...)
#define STAssertThrowsSpecific(expression, specificException, description, ...)
#define STAssertThrowsSpecificNamed(expr, specificException, aName, description, ...)
#define STAssertNoThrow(expression, description, ...)
#define STAssertNoThrowSpecific(expression, specificException, description, ...)
#define STAssertNoThrowSpecificNamed(expr, specificException, aName, description, ...)
#define STFail(description, ...)
#define STAssertTrueNoThrow(expression, description, ...)
#define STAssertFalseNoThrow(expression, description, ...)
参考情報
OCUnit については [SM gakusyuu]; サイトが詳しい。Cocoaアプリから Static Library、テストケースのデバッグ、果てはコードカバレッジ計測まで網羅されていて非常に参考になった。
OCUnitの使い方(Cocoa Application編) - [SM gakusyuu];
OCUnitの使い方(Static Library編) - [SM gakusyuu];
OCUnitの使い方(デバッグ編) - [SM gakusyuu];
OCUnitの使い方(コードカバレッジ計測) - [SM gakusyuu];
公式リファレンス(iOS向け)
iOS Development Guide: Unit Testing Applications
ソースコード
GitHub からどうぞ。
StudyUnitTest at 2010-11-22 from xcatsan's iOS-Sample-Code - GitHub