酒と泪とRubyとRailsと

Ruby on Rails と Objective-C は酒の肴です!

Objective-CのUnit Testフレームワーク GHUnitの導入手順

Objecitve-CのUnit Testのフレームワークの中では、GHUnitが安定性の面でオススメなようです。ということで、GHUnitの導入にトライしたらドハマリしたので、今後のために導入の手順を残しておきます。


Objective-Cのテストフレームワーク

Objective-Cのテストフレームワークの比較は、iOS 向けTDD/BDDフレームワークやモックフレームワークの現状 - laiso - iPhoneアプリ開発グループ がよくまとまっています。ここでの結論は、SenTestingKitが公式でサポートされており、XCode/iOSのバージョンアップして使い続けられる点でオススメとのことでした。

一方、TECH-GYM(株式会社プラスアール)さんのブログでは、複数のフレームワークを試して、安定していたGHUnitを使い続けておられるっぽいです。

SenTestingKit/GHUnitを両方トライしましたが、GHUnitのほうが「テストを書きやすい」と感じたので、しばらくGHUnitを試してみたいと思っています。

CocoaPodsのインストール

拙著、Objective-Cのライブラリ管理 CocoaPodsの手順で、CocoaPodsをインストール。

GHUnitのインストール〜起動まで

まず、XCodeを起動してプロジェクトを作成して下さい。ここではプロジェクト名をsampleCocoaPodsとします。このプロジェクトにGHUnitのテストを作るためのターゲットを追加します。

Add target GHUnit 1

Add target GHUnit 2

Add target GHUnit 3

ここで一度XCodeを終了させて下さい。

今回のプロジェクトフォルダの直下のPodfileに以下を追加して、pod installを実行。

1
2
3
4
platform :ios, '6.0'
target :GHUnit do
    pod 'GHUnitIOS', '~> 0.5.6'
end

これが完了したら、XCodeでCocoaPodsのWorkspaceを開いて下さい。

スクリーンショット 2013-01-23 21.47.35

スクリーンショット 2013-01-23 22.13.53

コピペしやすいように下にも書いておきます。

1
2
3
4
5
6
int main(int argc, char *argv[])
{
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, @"GHUnitIOSAppDelegate");
    }
}

スクリーンショット 2013-01-23 22.17.51

スクリーンショット 2013-01-23 22.21.01

GHUnitでのテスト実行まで

続いて実際にGHUnitでテストを書いていきます。テストは前述のTECH-GYM(株式会社プラスアール)さんのブログのGHUnitを導入する | Technology-Gymが一番わかり易かったので、使わせていただいています。

テストをされる側のプロジェクト(sampleCocoaPods)でUtility.hUtility.mを作成します。作成するときはターゲットに注意して下さい。 また、継承するクラス(Subclass of)はNSObjectにして下さい。

スクリーンショット 2013-01-24 8.56.56

テストをされる側のクラスのヘッダファイルUtility.hは次の通りです。

1
2
3
4
5
6
7
#import <Foundation/Foundation.h>

@interface Utility : NSObject {
}
+ (NSString *)urlencode:(NSString *)text;
+ (NSString *)urldecode:(NSString *)text;
@end

つづいて、実装ファイルUtility.mです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#import "Utility.h"

@implementation Utility

+ (NSString *)urlencode:(NSString *)text
{
    return (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL,(CFStringRef)text,NULL,(CFStringRef)@"!*'();:@&=+$,/?%#[]",kCFStringEncodingUTF8));
}

+ (NSString *)urldecode:(NSString *)text
{
    return (NSString *)CFBridgingRelease(CFURLCreateStringByReplacingPercentEscapesUsingEncoding(NULL,(CFStringRef) text,CFSTR(""),kCFStringEncodingUTF8));
}
@end

次はGHUnit側です。GHUnit側で、UtilityTest.hUtilityTest.mを作成します。継承するクラス(Subclass of)は、GHTestCaseにして下さい。

ヘッダファイルUtilityTest.hを次のようにして下さい。

1
2
3
4
5
#import <GHUnitIOS/GHUnit.h>
#import "Utility.h"
@interface UtilityTest : GHTestCase {
}
@end

最後にGHUnit側の実装ファイルUtilityTest.mです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#import "UtilityTest.h"

@implementation UtilityTest
- (void)test_urlencode
{
    NSString *url1 = @"%e3%83%86%e3%82%b9%e3%83%88%e3%81%9d%e3%81%ae%e4%b8%80";
    url1 = [url1 uppercaseString];
    NSString *url2 = [NSString stringWithString:[Utility urlencode:@"テストその一"]];
    GHAssertEqualObjects(url1, url2, @"match!");

    NSString *url3 = @"%e3%81%93%e3%82%8c%e3%82%82%e3%80%8c%e3%81%a6%e3%81%99%e3%81%a8%e3%80%8d%e3%81%a0%e3%81%a3%e3%81%9f%e3%82%8a";
    url3 = [url3 uppercaseString];
    NSString *url4 = [NSString stringWithString:[Utility urlencode:@"これも「てすと」だったり"]];
    GHAssertEqualObjects(url3, url4, @"match!");
}

- (void)test_urldecode
{
    NSString *url1 = [NSString stringWithString:[Utility urldecode:@"%e3%83%86%e3%82%b9%e3%83%88%e3%81%9d%e3%81%ae%e4%b8%80"]];
    url1 = [url1 uppercaseString];
    NSString *url2 = @"テストその一";
    GHAssertEqualObjects(url1, url2, @"match!");

    NSString *url3 = [NSString stringWithString:[Utility urldecode:@"%e3%81%93%e3%82%8c%e3%82%82%e3%80%8c%e3%81%a6%e3%81%99%e3%81%a8%e3%80%8d%e3%81%a0%e3%81%a3%e3%81%9f%e3%82%8a"]];
    url3 = [url3 uppercaseString];
    NSString *url4 = @"これも「てすと」だったり";
    GHAssertEqualObjects(url3, url4, @"match!");
}
@end

これをRunすると下のような結果になると思います。

スクリーンショット 2013-01-24 9.22.41

GHUnitの導入〜テストの実行までは以上です^^

補足: 後からGHUnitをひもづける場合

GHUnit add target

Add target GHUnit 2

Add target GHUnit 3

スクリーンショット 2013-01-23 21.55.56

スクリーンショット 2013-01-23 20.43.16

スクリーンショット 2013-01-23 22.00.45

以下を追加。

-ObjC
-all_load

補足:「 Undefined symbols for architecture i386: OBJC_CLASS 」といったエラーが出る場合

プロジェクト => TARGETSのGHUnit => Build Phases => Compile Sourcesにimportしたいファイルをドラッグアンドドロップしてみて下さい。

お願い

Objective-C初心者なのでお見苦しい点が多々あるかと思います。もし間違っていたり等々、お気づきの点があればツッコミをお願い致します!

Special Thanks

GHUnitを導入する | Technology-Gym

How to setup GHUnit with CocoaPods - Junda Ong

GHUnitの使い方(Xcode4) - k_kinukawa’s diary

テスト環境

テスト環境は次の通りです。バージョンが違うとインストール方法がまったく異なることがあるので、動かなければグーグル大先生にお伺いをたてて下さい。

1
2
3
XCode: 4.5.2
iOS: 6.0
CocoaPods: 0.16.1

変更来歴

01/28 09:10 @ishkawaさんからコメントを頂いてPodfileを修正、QuartzCore.frameworkやlibPods.aとのヒモ付や、リンカフラグの設定はCocoaPodsが自動でやってくれるので、プロセスから外しました。(補足に残しています)

10秒でバイトが見つかるアプリ「Short.Works」作ってます!

iPhoneアプリ Short.Works
短期のアルバイトを10秒で探して、応募ができるiPhone/Androidアプリ『Short.Works』を9月リリース目標に開発しています。

どんなアプリ?

* ソーシャル上の「つながり」を通じて、友達や知り合いにアルバイトが拡がる
* 空いてる時間に「ボタンひとつ」で「すぐ」にアルバイトが見つかる
* スケジュールを登録すると、自分にあったアルバイトがレコメンドされる

一緒にアプリを良くしませんか?

もしアプリに興味を持って頂けるようなら、『メールアドレス contact@short.works』か『Twitter @shortworkus』にメッセージ下さい^^

1) iPhone / Android / Railsアプリ / インフラ構築の開発にご協力頂ける方
2) スマートフォンアプリやWebサイト、HTMLメールのデザインにご協力頂ける方
3) マーケティングや営業にご協力頂ける方
半日〜1日だけとか週末プロジェクトとか、ガッツリやってみたいとか相談のります。 報酬もテンポラリー、レベニューシェア、その他もろもろ何でも相談に乗ります!何でも言ってください。

押さえておきたい書籍

いかがだったでしょうか?
もし説明がわかりにくかったり、間違っている場所があればぜひ一言!

Comments