こんにちは、 株式会社ジェネシックス の徐 廷(@TonnyXu)です。iPhoneの共通モジュールのベストプラクティスに関してです。
文章が長くなりますので、5回に分けてお届けします。
今回は、5回目となります。
その1
■ 共通プロジェクトを作る
その2
■ コンシューマPJを作る
■ コンシューマPJで共通プロジェクトを引用
その3
■ 引用する後コンシューマPJでの必須設定
その4
■ コンシューマPJを実行する
その5
■ さらに
・ 共通プロジェクトに単体テストを追加
・ オープンソースライブラリを作る
■ さらに
コード品質を向上するために、単体テストは不可欠です。特に共通モジュールでバグがあると、影響は非常に大きなものになるので、単体テストをしっかり作ったほうが良いと思います。
・ 共通プロジェクトに単体テストを追加
iPhone SDKは3.0から、単体テストをサポートしています。では、共通モジュールに追加してみましょう。

図23:共通プロジェクトにテストtargetを追加
新しいTargetのタイプは「Unit Test Bundle」です。名前は「LogicTests」にしましょう。まずは図24のように、テストTargetの依存性を指定しましょう。

図24:テストTargetの依存関係画面
図24の依存関係の下の「+」ボタンを押してください。

図25:共通モジュールを依存先として追加
これで、単体テストのtargetができました。次はテストケースを追加しましょう。Testというグループを作って、右クリックして、Add New Files...を選択してください。

図26:テストケースを選択

図27:テストケースを追加
注意 所属targetはLogicTest *のみを選択してください。
テストケースのテンプレートが自動的に適用されます。下記のようなヘッダーファイルとコードファイルが自動的に生成されます。
GCDeviceTests.h//
// GCDevicesTests.h
// Common
//
// Created by Tonny Xu on 10/05/26.
// Copyright 2010 genesix, Inc. All rights reserved.
//
// See Also: http://developer.apple.com/iphone/library/documentation/Xcode/Conceptual/iphone_development/135-Unit_Testing_Applications/unit_testing_applications.html
// Application unit tests contain unit test code that must be injected into an application to run correctly.
// Define USE_APPLICATION_UNIT_TEST to 0 if the unit test code is designed to be linked into an independent test executable.
#define USE_APPLICATION_UNIT_TEST 0
#import <SenTestingKit/SenTestingKit.h>
#import <UIKit/UIKit.h>
//#import "application_headers" as required
@interface GCDevicesTests : SenTestCase {
}
#if USE_APPLICATION_UNIT_TEST
- (void) testAppDelegate; // simple test on application
#else
- (void) testMath; // simple standalone test
#endif
@end
GCDeviceTests.m
//
// GCDevicesTests.m
// Common
//
// Created by Tonny Xu on 10/05/26.
// Copyright 2010 genesix, Inc. All rights reserved.
//
#import "GCDevicesTests.h"
@implementation GCDevicesTests
#if USE_APPLICATION_UNIT_TEST // all code under test is in the iPhone Application
- (void) testAppDelegate {
id yourApplicationDelegate = [[UIApplication sharedApplication] delegate];
STAssertNotNil(yourApplicationDelegate, @"UIApplication failed to find the AppDelegate");
}
#else // all code under test must be linked into the Unit Test bundle
- (void) testMath {
STAssertTrue((1+1)==2, @"Compiler isn't feeling well today :-(" );
}
#endif
@end
ヘッダーファイルの「USE_APPLICATION_UNIT_TEST」を0に設定しましょう。この時点では本番のテストケースをまだ書いていませんが、テストを実行することはできます。では、プロジェクトの実行targetを下図のようにLogicTestに変更しましょう。

図28:テストケースのtargetに設定
「テストケースを実行する」というより実はコンパイルするだけです。Active targetをLogicTestに設定したら、コンパイル(Build→build)してみましょう。間違っていなければ、ビルド結果画面を開く(Build->Build Results)と、下図のような画面が出てきます。

図29:テストケースの実行結果
クラスGCDeviceをテストするために、GCDevice.mファイルをLogicTests Targetに追加しなければいけません。GCDevice.mファイルを右クリックして, 出てくるメニューのGet Infoをクリックしましょう。下図の画面が出てきます。

図30:テスト対象クラスの.mファイルをテストtargetに追加
図30のように、二つのtargetの左側のチェックボックスを全部チェックしてから、GCDeviceTests.mファイルに新しいテストケースを追加しましょう。
GCDeviceTests.h//...上省略 #else - (void) testMath; // simple standalone test - (void) testIsIPad; #endif //...下省略
GCDeviceTests.m
//...上省略
- (void) testMath {
STAssertTrue((1+1)==2, @"Compiler isn't feeling well today :-(" );
}
- (void) testIsIPad{
STAssertFalse( [GCDevice isIPad], @"単体テストとしてはFalseしかない.");
}
//...下省略
追加したテストケースの実行結果を見てみましょう。

図31:testIsIPadのテストケース実行結果
これで、共通モジュールの作成、利用、テストの説明がすべて終わりました。
・ オープンソースライブラリを作る
この共通モジュールは自分のプロジェクトで使えるだけではなく、ほかの人のプロジェクトでも動きます。もしこの共通モジュールを公開したければ、最低限libCommon.aファイルとすべてのヘッダーファイル(テストケースのヘッダーファイルを除く)を一緒にアーカイブして提供すれば、だれでも手軽に使えます。本文で使用したサンプルコードです。
オープンソースライブラリにするなら、このプロジェクトのすべてのフォルダとファイル(buildフォルダを削除したほうが良いです)をGoogle CodeあるいはGitHubにアップロードしましょう。
皆さんが作ったすばらしいライブラリをお待ちしております。

