先日、Bambooを導入し、Javaサーブレットの継続的ビルド&テストに使ってきましたが、そろそろ、iOSアプリにも使いたいと思い、設定しました。引っかかるポイントがいくつかあったので、この記事にまとめてみました。
■マシンの準備
XcodeはOS Xが必須なので、BambooをOS X上で動かします。私の場合は、OS X 10.8.4 (Moutain Lion) Serverを使いました。
■Xcodeの準備
Mac App Store経由でXcodeをインストールします。インストールしたら、Xcodeを起動して、「Xcode」メニューから「Preference」を選択し、「Downloads」タブの「Components」タブを開き、「Command Line Tools」をインストールします。
次に、コマンドラインでXcodeを動かせるようにするため、ターミナルで次のように入力します。
[cc]xcodebuild -license[/cc]
Xcodeの使用許諾が表示されるので、確認して、最後に「agree」(ライセンスに同意するという意味です)と入力します。
■ios-simをインストール
iOSシミュレータをコマンドラインから使えるようにするため、ios-simをインストールします。私は、Homebrew経由でインストールしました。Homebrewはターミナルで次のように入力してインストールします。
[cc]ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"[/cc]
Homebrewのインストールが終わったら、次のように入力して、ios-simをインストールします。
[cc]brew install ios-sim[/cc]
■プラグインインストール
BambooからXcodeのプロジェクトをビルドできるようにするため、次のプラグインをインストールします。
Bamboo iOS, Cocoa and Xcode Support
https://marketplace.atlassian.com/plugins/com.atlassian.bamboo.plugins.xcode.bamboo-xcode-plugin
■Xcodeのプロジェクト設定
テスト対象のプロジェクトを設定します。Xcodeの内蔵テストフレームワークを使用するようにプロジェクトを作成します。私の場合は、プロジェクトを作成するときに「Include Unit Tests」オプションをONにしたときに、自動的に作られるテストバンドルをそのまま使用しました。
次のドキュメントに書かれているように、ユニットテストのターゲットのスクリプトを変更します。
Xcode – Bamboo Latest – Atlassian Documentation
https://confluence.atlassian.com/display/BAMBOO/Xcode
「Include Unit Tests」をONにして作成されたターゲットの場合は、ターゲットの設定を表示して、「Build Phases」の「Run Script」を開き、その中に書かれているスクリプトを次のように置き換えます。
[cc]if [ "$RUN_UNIT_TEST_WITH_IOS_SIM" = "YES" ]; then test_bundle_path="$BUILT_PRODUCTS_DIR/$PRODUCT_NAME.$WRAPPER_EXTENSION" /usr/local/bin/ios-sim launch "$(dirname "$TEST_HOST")" --setenv DYLD_INSERT_LIBRARIES=/../../Library/PrivateFrameworks/IDEBundleInjection.framework/IDEBundleInjection --setenv XCInjectBundle="$test_bundle_path" --setenv XCInjectBundleInto="$TEST_HOST" --args -SenTest All "$test_bundle_path" echo "Finished running tests with ios-sim" else "${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests" fi[/cc]
■ジョブの設定
ここからBamboo上での設定です。Xcodeでビルドするためにタスクを追加します。先ほどインストールしたプラグインによって、タスクの「Builder」に「Xcode」が追加されているので、それをジョブに追加します。
追加したタスクの設定を行います。
まず、「Apple SDK」から使用するSDKを選択します。マシンにセットアップされているものが自動的に検出されるはずなのですが、私の環境では検出されませんでした。ですので、「Add new executable」を押し、追加します。
たとえば、iOS SDK 6.1を使う場合は次のように設定します。
入力可能な値は、ターミナルで次のように入力すると確認できます。
[cc]xcodebuild -showsdks[/cc]
私の環境では次のように表示されました。
[cc]OS X SDKs: Mac OS X 10.7 -sdk macosx10.7 OS X 10.8 -sdk macosx10.8 iOS SDKs: iOS 6.1 -sdk iphoneos6.1 iOS Simulator SDKs: Simulator - iOS 6.1 -sdk iphonesimulator6.1[/cc]
次に、Generalの「Build all targets」のチェックを外し、「Target」にテストバンドルのターゲット名を入力します。たとえば、プロジェクトの設定に次のように表示されている場合は、「RKCheckTests」と入力します。
* 19:34 追加 : もちろんテストだけではなくipaファイルをテスト担当者に配布することまで考慮する場合は「Build all targets」です。
後は、「Clean the project before building」や「Report test results」「Run tests in iOS simulator」などをONにします。
次に、「Project」のディスクロージャーを開いて、プロジェクトファイルの名前と使用する設定を入力します。(たとえば、「Project」は「RKCheck.xcodeproj」、「Configuration」は「Debug」など)
なお、ワークスペースを手動で作成しているときは、「Project」には何も入力せず、「Workspace」の方に入力します。「Project」と「Workspace」の両方とも同時には設定できません。どちらか片方にします。
次に、「iOS development」の「Run tests in iOS simulator」をONにします。
さらに、クローン(チェックアウト)した直下にプロジェクトファイルがない場合には、「Advanced」を開いて、「Working sub directory」にクローン(チェックアウト)した直下からの相対パスでプロジェクトファイルのあるディレクトリを指定します。
たとえば、図のようなディレクトリ構成の場合は「iOS/RKCheck」と入力します。
(左端がクローンした直下)
これで完了です。後は、このプランを有効にすると実行できます。
■実はiOSアプリのテスト特有の事象がありました
実は、上記のように設定しただけだと、私の環境では動きませんでした。ローカルでXcodeからテストをしたときや、ターミナルでxcodebuildを実行したときに、正しくテストコードが動くものをコミットしても、なぜか、Bambooから実行すると、テストコード自体が検出されないという事象が起きました。
実は、テストのときにios-sim経由で、iPhoneシミュレータも組み合わせてユニットテストが行われます。これは、ローカルで実行したときも同じです。このときに、Bamboo側は、ビルドもシミュレータの実行も、Bambooを動かしているユーザー権限で動作します。そのため、ログインしているユーザーとBambooの実行ユーザーが異なると、正しく動きません。
そのため、bambooを動かすユーザーでサーバーにログインしておく必要があります。
私の場合は、外部からは接続できない内部専用のサーバーなので、ログインしている状態で、スクリーンロックをかけていますが、外部から接続可能なサーバーの場合は、他のセキュリティソリューションも組み合わせた方が良いと思います。
また、ログインしていない状態で実行すると次のようにログに出力され、失敗してしまいます。
04-8-2013 18:02:09 Could not start simulator session: Error Domain=DTiPhoneSimulatorErrorDomain Code=5 "Operation failed with underlying error 4294956486." UserInfo=0x7fe4e4d04d60 {NSLocalizedDescription=Operation failed with underlying error 4294956486., NSUnderlyingError=0x7fe4e4a02df0 "The operation couldn’t be completed. (OSStatus error -10810.)"}