2013年7月1日

【iPhone】GHUnitでUnitTestをする



Jenkinsサーバを立てているなら、ビルドだけで無くUnitTestもしてみたい。
と思い、iOSのテストコードを書く事にいたしました。

UnitTestのFrameworkはいろいろあるのですが、
なんだからGHUnitが良さそうです。

GHUnitのインストール

まずはGHUnitのインストールから、
GHUnitはGitHubにありますので、探しましょう。

git clone https://github.com/gabriel/gh-unit.git
cd gh-unit/Project-iOS/
make

これでFramework完成。


テストターゲットの作成

Xcodeのテストしたいプロジェクトから、Add Targetでターゲットを追加します。
今回はUnitTestというターゲットとでもしましょう。

ターゲットを追加したら、AppDelegate.h、AppDelegate.m、InfoPlist.stringを削除します。

次に、ターゲットを指定し、Build Settingsで、
Valid Architechturesにi386(iOSシミュレータ)を追加します。


そして、Other Linker Flagsに-ObjC -all_loadを追加します。


最後にフレームワークを追加します。
先ほどビルドしたGHUnitiOS.frameworkをプロジェクトのFrameworksへコピー。
Build PhasesにはGHUnitiOS.frameworkも追加されている事を確認して下さい。
追加されていなければ、FrameworksからGHUnitiOS.frameworkを選択し、
右のTarget MembershipでUnitTestターゲットをチェックして下さい。

また、UnitTestターゲットのBuild Phasesから、QuartzCore.frameworkを追加します。
一旦ここまでで事前準備は完了です。

テスト設定

これだけで済めばいいのですが、実行出来なかったり、バグがあったりいろいろでした。
何でかなぁと調べてて、私が実行出来た設定のメモを残します。

まずはmain.mを編集します。
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import <GHUnitIOS/GHUnit.h>

@interface MyUIApplication : UIApplication
@end

@implementation MyUIApplication

- (id)init
{
    self = [super init];
    if (self && getenv("GHUNIT_CLI") && [[[UIDevice currentDevice] systemVersion] doubleValue] >= 6.0) {
        __block BOOL done = NO;
        NSOperationQueue * queue = [[ NSOperationQueue alloc ] init ];
        [queue addOperationWithBlock:^{
            int status = [GHTestRunner run];
            if (status != 0) {
                NSString *reason = [NSString stringWithFormat:@"failed to test %d", status];
                @throw [NSException exceptionWithName:@"TestFailure" reason:reason userInfo:nil];
            }
            done = YES;
        }];
        
        while( !done ) {
            [[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 5] ];
        }
    }
    
    return self;
}

@end

int main(int argc, char *argv[])
{
    @autoreleasepool {
        return UIApplicationMain(argc, argv, @"MyUIApplication", @"GHUnitIOSAppDelegate");
    }
}

テストコード

同期テストの場合はGHTestCase、非同期テストの場合はGHAsyncTestCaseクラスを使います。
テストディレクトに新規Objective-Cのクラスファイルを作り、
テストコードを書いていきます。

こちらは後日詳しく説明しようと思います。

実行

実行する為にMakefileを作ります。
clean:
    -rm -rf build/*

test:
    GHUNIT_CLI=1 xcodebuild -target UnitTest -configuration Debug -sdk iphonesimulator build    

と作成しました。

最後にテストを実行する為のコマンド
make clean && make test
で実行出来ました。

JUnit形式のXMLを出力させ、Jenkinsで表示なんて事もやってます。

そのあたりはおいおい解説していきますね。