ラベル OCUnit の投稿を表示しています。 すべての投稿を表示
ラベル OCUnit の投稿を表示しています。 すべての投稿を表示

[iOS] OCUnitで単体テスト〜アプリケーションテスト

2010年11月23日火曜日 | Published in | 0 コメント

このエントリーをはてなブックマークに追加

[前回] Cocoaの日々: [iOS] Static Library (6) OCUnitで単体テスト

iOS Development Guide: Unit Testing Applications によればXcodeでOCUnit を使ったテストは2通りある。

  • Logical Tests
  • Application Tests

前回やったテストが Logical Tests にあたり、これはビルド時にテストを実行する。一方、Application Tests はビルド時ではなくアプリケーション実行時にテストを実行する。今回はこれを試してみた。

こんなプロジェクトを作る。ApplicationTestSampleTesting がアプリケーションテスト用ターゲット。
アプリを実行するとこんな内容がデバッグコンソールへ出力される。


手順


手順は iOS Development Guide: Unit Testing Applications に分かりやすく記載されている。今回は新規にプロジェクトを作成して試してみる。

1. 新規プロジェクト

View-based Application テンプレートを使って新規にプロジェクトを作成する。名前を ApplicationTestSample とした。


2. アプリケーションテスト用ターゲット作成

デフォルトで用意されるターゲットを複製する(右クリックで「複製」を選択)。名前は <アプリケーション名>Testing とする。


3. テストケース用ターゲット追加

続いてテストケース用ターゲット(バンドル)を追加する。「ターゲット」を右クリックして「追加」→「新規ターゲット」でダイアログを開き "Unit Test Bundle" を追加する。名前は "AppTests" とする(名前の最後を "Tests" としておく)。

次にこのターゲットをドラッグ&ドロップでアプリケーションテスト用ターゲット "ApplicationTestSampleTesting" に追加する。
さらい "Products" 内の "AppTests.octest" を "ApplicationTestSampleTesting" の「バンドルリソースをコピー」へドラッグ&ドロップで追加する。
これでアプリケーションにテストバンドルが格納され、実行時にテストが走るようになる。


4. テストコード作成

テストケース用のクラスを新規作成する。
名前を AppTest として追加先のターゲットは "AppTests" とする。
中身はこんな感じ。
#import <SenTestingKit/SenTestingKit.h&;gt;
#import <UIKit/UIKit>

@interface AppTests : SenTestCase {

}

@end
#import "AppTests.h"

@implementation AppTests

- (void) testFail {
 STFail(@"Must fail to succeed.");
}

@end

5. 実行

さて実行してみよう。実機を接続して実行する。

出た。デバッグコンソールに表示されるので非常に見づらい
Xcodeの「デバッグ」の設定でデバッグコンソールの色が変えると多少ましにはなる(あんまりかわらないか)。
こんな感じ。

なお、アプリケーションテストは実機でしか試せない。
シミュレータで実行しようとするとビルド時にテストコードが走ってしまいテストに失敗した場合は実行ができないので注意。これはリファレンスにちゃんと書いてあるのだが見落としていて最初はまった。


ソースコード


GitHub からどうぞ。
ApplicationTestSample at 2010-11-23 from xcatsan's iOS-Sample-Code - GitHub


参考情報


iOS Development Guide: Unit Testing Applications
単体テストの公式リファレンス

Cocoa with Love: A sample iPhone application with complete unit tests
公式リファレンスの補足的な資料となっている

[iOS] Static Library (6) OCUnitで単体テスト

2010年11月22日月曜日 | Published in | 0 コメント

このエントリーをはてなブックマークに追加

[前回] 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

人気の投稿(過去 30日間)