FrontPage

2010/09/21からのアクセス回数 8868

iPhone SDKのUnitTestは中途半端

iPhone SDKにもUnitTest用のクラスとプロジェクトテンプレートが提供されています。

UnitTest バンドルの新規作成

iPhone用のアプリケーションプロジェクト(ここではCopyTextを使います)に、UnitTestバンドルを追加します。

  • 「グループとファイル」からプロジェクト名を選択し、右クリックで「追加」→「新規ターゲット」を選択します
  • 「Cocoa Touch」から「Unit Test Bundle」を選択し、「次へ」ボタンを選択
  • ターゲット名を入力します(ここではUnitTestsとします)

単体テストクラスを作成

次に単体テスト用のクラスを作成します。

  • プロジェクト名を右クリックで「追加」→「新規グループ」を選択し、グループ名を入力(ここでは「Test Classes」と)します。
  • 「Test Classes」を右クリックし、「追加」→「新規クラス」を選択します
  • 「Objective-C test case class」を選択し、「次へ」ボタンを選択
  • クラス名を入力します(ここではMyTestCase)とし、ターゲットをUnitTestsとします。

今回は、APPLICATION_UNIT_TESTを使わないので、MyTestCase.hのdefine文を変更します。

#define USE_APPLICATION_UNIT_TEST 0

単体テストの実行

単体テストの実行は、

  • ターゲットを「UnitTests」を選択
  • 「実行」メニューから「ビルド」を選択します

単体テストに失敗すると「CopyTest-ビルド結果」のウィンドウにエラーが表示されるのですが、 正常終了の場合は、Build Succeededとしか出力されません。

「何となく」物足りないのと、エラーが発生した場合デバッグすることができないのが、 私が「中途半端」と感じるところです。

試しにtestMathの1+1を1+2に変更し、ビルドして見てください。

failed.png

のようなエラーが「スクリプト実行」の結果として表示されます。 残念ながらこのままではtestMathをデバッグできません。

かっこ悪いデバッガの使い方

とても残念なのですが、色々調べた結果単体テストのデバッグには、次ような作業がプロジェクト毎に必要になります。

  • 実行可能ファイルにotestを追加
  • otestの情報として、2個の引数と8個の環境変数の設定が必要

この方法は、Scitt Densmore氏の以下のURLを参照しました。

otestの設定

octestの追加手順は以下の通りです。

  • 「実行可能ファイル」を選択し、右クリックで「追加」→「新規カスタム実行可能ファイル」を選択
  • 「実行可能ファイル名」をotest、実行可能ファイルのパスとして、以下の値をセット
    /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.0.sdk/Developer/usr/bin/otest
    

otestの設定

  • otestを選択し、右クリックで「情報を見る」を選択し、引数タブを選択します

arg_setting.png

のように引数と環境変数を設定します。

引数は、2個目の引数は、単体テストのターゲット名+.octestとします。

-SenTest All
UnitTests.octest

環境変数は、

NameValue
DYLD_ROOT_PATH$(SDKROOT)
DYLD_FRAMEWORK_PATH${BUILD_PRODUCTS_DIR}:${SDK_ROOT}:${DYLD_FRAMEWORK_PATH}
IPHONE_SIMULATOR_ROOT$(SDKROOT)
CFFIXED_USER_HOME$(HOME)/Library/Application Support/iPhone Simulator/User/
OBJC_DISABLE_GCYES
DYLD_LIBRARY_PATH${BUILD_PRODUCTS_DIR}:${SDK_ROOT}:${DYLD_LIBRARY_PATH}
DYLD_NEW_LOCAL_SHARED_REGIONSYES
DYLD_NO_FIX_PREBINDINGYES

デバッガの起動

デバッガを起動する前に、もう一度、ターゲットUnitTestsを実行しておきます。

次に、

  • testMathの最初の行にブレークポイントを設定
  • otestを選択し、右クリックで「ブレークポイントを使ってotestを開始」を選択します。
  • 実行からデバッガを表示をクリックすると以下のデバッガの画面になります。

debugger.png

これで、無事デバッガが使えるようになりました。

hamcrestの準備

hamcrestは、単体テストで判定をする時の便利な機能を集めたパッケージです。

hamcrestの大きな特徴は、メソッド名称が英語に近い表現になっていることです。

assertThat(aaaa, is(not(equalTo(bbbb))));

は、カッコとカンマを全部取り除くと assert that aaaa is not equal to bbbb.となり、 英語として意味のわかるように作られています。*1

インストール手順

残念ながら、hamcrestにはiPhone SDK用のパッケージはありません。

ここでは、SVNを使ったソースからの作成方法を紹介します。

  • ホームディレクトリにlocal/OCHamcrestを作成
  • SVNを使ってソースをダウンロードします
    svn checkout http://hamcrest.googlecode.com/svn/trunk/ hamcrest-read-only
    
  • /local/OCHamcrest/hamcrest-read-only/hamcrest-objectivec/SourceのOCHamcrest.xcodeprojをダブルクリック

  • ターゲットのOCHamcres-iOSをテスト環境と同じDebugとSimulatorにセットし、ビルドします

使い方

hamcrestの使い方*2は、簡単です。

ソースの最初に以下の2行を追加するだけです。

#define HC_SHORTHAND
#import <OCHamcrest/OCHamcrest.h>

最初のHC_SHORTHANDは、メソッドの先頭にHC_を付けないで使用するためのおまじないです。

ライブラリで提供する機能は以下の通りです。

  • 基本
    • aynthing : 常にマッチする
    • describedAs : カスタムfailureを記述するためのデコレータ(可読性のためのメソッド)
    • is : 読みやすくするためのデコレータ
  • 論理
    • allOf : すべてがマッチしたときに、マッチ(真となる)
    • anyOf : いづれかたがマッチしたときに、マッチ
    • isNot : マッチしなかったときにマッチ
  • オブジェクト
    • equalTo : オブジェクトの一致をisEqualメソッドを使ってチェック
    • hasDescription : テストに関する記述を追加
    • instanceOf, isCompatibleType : 型の一致をチェック
    • notNilValue, nilValue : nilのチェック
    • sameInstance : 同一インスタンスのチェック
  • 集合
    • hasEntry, haskey, hasValue : NSDictionaryのcontains entry, key, value のチェック
    • hasItem, hasItems : 集合がアイテムを含むか否かのチェック
  • 数値
    • closeTo : 浮動小数点の値が近いかどうかのチェック
    • greaterThan, greaterThanOrEqualTo, lessThan, LessThanOrEqualTo : 大小のチェック
  • テキスト
    • equalToIgnoringCase : 大文字小文字の区別無く文字の一致をチェック
    • equalToIgnoringWhiteSpace : 空白の違いを無視して文字の一致をチェック
    • containsString, endsWith, startsWith : 文字の一致をチェック

hamcrestの使用例

hamcrestを使うには、

  • 外部フレームワークをセットし、インクルードファイルパスをセットする
  • 使用するライブラリがiPhone OS用のスタティックライブラリを使用するためにhamcrestプロジェクトをドラッグする
  • 外部リンクフラッグに-ObjC, -all_load, -lstdc++ を追加する

必要があります。

外部フレームワークの追加は、プロジェクトを選択し、右クリックで「追加」→「既存のフレームワーク」を選択し、「その他の追加」からOCHamcrestのSource/build以下のDebug/OCHamcrest.frameworkを選択します。

次に、OCHamcrestのXCodeプロジェクトをテストしたいプロジェクトにドラッグしますと、

drag_proj.png

のダイアログが表示されるので、ターゲットを単体テスト(UnitTests)であることを確認します。

次に、libochamcrest.aの左端のチェックボックスをセットします。

hamcrest_ex.png

最後にターゲットのUnitTestsを選択し、「情報を見る」を選択し、ビルドタグから外部リンクを選択し、「他のリンカフラグ」をダブルクリックし、他のフラグの後に-ObjC, -all_load, -lstdc++ を追加する。

テストプログラムは、以下を参考に入力してください。

#import "GTMSenTestCase.h"
#define HC_SHORTHAND
#import <OCHamcrest/OCHamcrest.h>
 
@interface ExampleWithAssertThat : SenTestCase
@end
 
@implementation ExampleWithAssertThat
 
- (void) testUsingAssertThat
{
    assertThat(@"xx", is(@"xx"));
    assertThat(@"yy", isNot(@"xx"));
    assertThat(@"i like cheese", containsString(@"cheese"));
}
 
@end

OCMockの準備

iPhone/最初の一歩でもお話したように、iPhoneの処理はViewControllerを中心に作られているため、 iPhoneシミュレータでWindowを表示しなければ、動作をチェックすることができません。

単体テストでは、OCMockのモック機能を使ってWindowを実際に表示することなく、テストが可能に なります。

OCMockには、

  • expectとverifyを使った検証機能
  • stubを使ったモック機能

があります。

インストール手順

OCMockは、以下のURLから「Download」タグをクリックして、

http://www.mulle-kybernetik.com/software/OCMock/

iPhone用の場合には、Mac OS X 10.6以降が必要ですから、ocmock-1.70.dmgをダウンロッドしてください。

ダウンロードしたOCMockは、システムではなくユーザのローカルディレクトリに入れることにします。ここでは、

  • $HOME/local/

に入れます。

OCMock 1.70/Source/ocmock-1.70にあるOCMock.xcodeprojをダブルクリックします。

ターゲットをOCMockPhoneSimに切り替えて、Debug版のlibOCMock.aを作成します。

ocmock_proj.png

OCMockの使用例

OCMockを使うには、ヘッダファイルとライブラリをセットする必要があります。

  • ヘッダは、$HOME/local/OCMock 1.70/Source/ocmock-1.70/Release/OCMock.frameworkを使用
  • ライブラリは、OCHamcrestと同様にOCMock.xcodeprojをドラッグして使用

ここで注意することは、OCMock.frameworkのライブラリを使用しないように、プロジェクトのファイル名一覧のOCMock.frameworkの右端のチェックを外すことです。

ocmock_setting.png

準備ができたら、OCMockのテスト用のメソッドを追加します。

// 以下のimport文を追加
#import <OCHamcrest/OCHamcrest.h>
#import <OCMock/OCMock.h>

// テスト用メソッドは以下の通り
- (void)testReturnsStubbedReturnValue
{
	id mock = [OCMockObject mockForClass:[NSString class]];
	
    [[[mock stub] andReturn:@"megamock"] lowercaseString];
    id returnValue = [mock lowercaseString];
	
    assertThat(returnValue, is(@"megamock"));
}

これで、テスト駆動型開発の準備が整いました。

コメント

この記事は、

選択肢 投票
おもしろかった 4  
そうでもない 0  
わかりずらい 3  

皆様のご意見、ご希望をお待ちしております。


(Input image string)


*1 hamcrestについては、java版ですが都元ダイスケさんのページ http://d.hatena.ne.jp/daisuke-m/20090710/1247181113 を参考にさせて頂きました。
*2 詳しくは http://code.google.com/p/hamcrest/wiki/TutorialObjectiveC を参照

添付ファイル: fileocmock_setting.png 1363件 [詳細] fileocmock_proj.png 1337件 [詳細] filehamcrest_ex.png 1420件 [詳細] filedrag_proj.png 1402件 [詳細] filedebugger.png 1383件 [詳細] filearg_setting.png 1341件 [詳細] filefailed.png 1265件 [詳細]

トップ   編集 凍結解除 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2012-08-13 (月) 13:45:07 (4275d)
SmartDoc