GitLabにはCI(Continuous Integration: 継続的インテグレーション) 機能があります。GitLabのCIを使えば、CI専用の別ソリューションを導入せずに、継続的インテグレーションを行えます。
そこで、GitLabにコードをプッシュしたときに、XCTestを動かして、macOSアプリやiOSアプリのユニットテストを実行することにしました。
この記事では、そのときに行った設定方法を紹介します。
Runnerの登録
GitLabのCI/CDはRunnerが動いて処理を実行します。Runnerにはプロジェクト間で共有する「Shared Runner」と、特定のプロジェクト専用の「Specific Runner」があります。
今回は複数のプロジェクト(リポジトリ)から使用したいので、「Shared Runner」を登録しました。
Runnerのインストール
XCTestを実行するために使用するRunnerなので、XCTestを実行するMacにインストールします。ここでは、Mac Miniを使いました。
macOSへのGitLab Runnerのインストール方法は公式サイトに書かれています。
ダウンロードするバイナリは、Intel Mac版とApple Silicon版とで異なります。ターミナルからcurl
でダウンロードします。
- Intel Mac版
sudo curl --output /usr/local/bin/gitlab-runner "https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-darwin-amd64"
- Apple Silicon版
sudo curl --output /usr/local/bin/gitlab-runner "https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-darwin-arm64"
ダウンロードされたRunnerは/usr/local/bin/gitlab-runner
に保存されます。
sudo chmod +x /usr/local/bin/gitlab-runner
cd ~
gitlab-runner install
gitlab-runner
のロケールを設定します。~/Library/LaunchAgents/gitlab-runner.plist
ファイルを開きます。このファイルはgitlab-runner install
によって作成されます。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- 省略 -->
<key>EnvironmentVariables</key>
<dict>
<key>LC_ALL</key>
<string>en_US.UTF-8</string>
</dict>
</dict>
デフォルトの出力先は、通常ユーザーには書き込み権限がないディレクトリのため、gitlab-runner
が起動しません。書き込みできるように、StandardOutPath
とStandardErrorPath
の値を書き込み可能なファイルパスに変更します。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- 省略 -->
<key>StandardOutPath</key>
<string>/Users/USER_NAME/.gitlab-runner/gitlab-runner.out.log</string>
<key>StandardErrorPath</key>
<string>/Users/USER_NAME/.gitlab-runner/gitlab-runner.err.log</string>
gitlab-runner start
Runnerの登録
MacにインストールしたRunnerをGitLabに登録します。
(1) Admin Area
のRunners
を開きます。
(2) Register an instance runner
をクリックし、Show runner installation and registration instructions
をクリックします。

(3) 詳細手順が表示されるので、Environment
からmacOS
を選択し、Command to register runner
という欄の横のコピーボタンをクリックして、コマンドをコピーし、Close
をクリックして閉じる。

(4) RunnerをインストールしたMac上のターミナルで、(3)でコピーしたコマンドをsudo
なしで実行する。Mac上でXCTestを実行するときは、ユーザーモードで動かす必要があるので、sudo
なしで実行する必要があります。
実行すると、設定を対話型で聞かれるので、順番に入力していきます。
(5) GitLabのURLを入力します。
Runtime platform arch=amd64 os=darwin pid=10297 revision=76984217 version=15.1.0
Running in system-mode.
Enter the GitLab instance URL (for example, https://gitlab.com/):
[http://code.rkdev.corp/]:
(6) 登録トークンを確認されます。コマンド実行時に既にトークンを指定しているので、Enterキーを押すだけでOKです。
Enter the registration token:
[-ABCDEFG4567890YZABC]:
(7) Runnerの説明を指定します。とりあえず、マシン名を入力しました。
Enter a description for the runner:
[MacMini2020.local]: MacMini2020
(8) Runnerに指定するタグを入力します。私の場合は、
- Macである
- Intel Macである
- OSは常に最新を使う予定である
これらを踏まえて、次の3つのタグを設定しました。
- mac
- mac-intel
- mac-intel-latest
Enter tags for the runner (comma-separated):
mac,mac-intel,mac-intel-latest
(9) メンテナンス用のメモを指定します。特にないので空欄のままにしました。
Enter optional maintenance note for the runner:
(10) Executerを設定します。公式サイトにmacOSアプリやiOSアプリの場合はshell
を使うように書かれているので、shell
を指定します。
Registering runner... succeeded runner=-ABCDEFG
Enter an executor: custom, parallels, shell, ssh, kubernetes, docker, docker-ssh, virtualbox, docker+machine, docker-ssh+machine:
shell
(11) 登録が成功すると次のように出力されます。
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!
(12) Admin Area
のRunners
ページを再読込すると、登録したRunnerが表示されます。

CI/CDの設定
テスト用のリポジトリとコードを用意してCI/CDの設定を行います。
テストコード
ここでは、GitLabのCIによって、XCTestが動くことを確認したいだけなので、次のような必ずエラーになるテストコードと必ず成功するテストコードを入れたユニットテストにしました。何かをテストしているわけではなく、XCTestを動かすだけなので、テストコードと呼ぶのも憚れますが。。。
import XCTest
@testable import CITest
class CITestTests: XCTestCase {
override func setUpWithError() throws {
}
override func tearDownWithError() throws {
}
func testExample() throws {
XCTFail("TEST FAILURE")
}
func testSuccess() throws {
XCTAssertTrue(true);
}
}
Shared Runnerを有効化する
リポジトリ単位で、Shared Runnerを有効化する必要があります。
(1) プロジェクトのSettings
のCI/CD
を開く。
(2) Runners
のExpand
を開く。
(3) Enable shared runners for this project
をオンにする。

CI/CDの設定ファイルを追加する
次のように操作して、CI/CDの設定ファイルを追加します。
(1) Webブラウザでリポジトリのページを開き、Set up CI/CD
リンクを開く。

(2) Create new CI/CD pipeline
をクリックする。

(3) Browse templates
をクリックし、Swift.gitlab-ci.yml
を開き、内容をコピーする。
(4) 自分のリポジトリのPipeline Editorに戻り、コピーした設定を貼り付ける。
(5) Xcodeのプロジェクトファイル名、スキーム名などを変更する。例えば、次の設定ファイルは以下の値を変更しています。
設定 | 値 |
---|---|
-project | CITest.xcodeproj |
-scheme | CITest |
-destination | iOS Simulator,name=iPhone 13,OS=15.5 |
tags | mac-intel-latest |
-archivePath | build/CITest |
-archivePath | build/CITest.xcarchive |
-exportPath | build/CITest.ipa |
-exportProvisioningProfile | “” |
paths: | build/CITest.ipa |
stages:
- build
- test
- archive
- deploy
build_project:
stage: build
script:
- xcodebuild clean -project CITest.xcodeproj -scheme CITest | xcpretty
- xcodebuild test -project CITest.xcodeproj -scheme CITest -destination 'platform=iOS Simulator,name=iPhone 13,OS=15.5' | xcpretty -s
tags:
- mac-intel-latest
archive_project:
stage: archive
script:
- xcodebuild clean archive -archivePath build/CITest -scheme CITest
- xcodebuild -exportArchive -exportFormat ipa -archivePath "build/CITest.xcarchive" -exportPath "build/CITest.ipa" -exportProvisioningProfile ""
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
artifacts:
paths:
- build/CITest.ipa
tags:
- mac-intel-latest
CIによるテストのみが必要で、アーカイブは不要な場合には、archive_project
ジョブを削除して、次のような設定ファイルにします。私の場合はこちらが必要でした。
stages:
- build
- test
- archive
- deploy
build_project:
stage: build
script:
- xcodebuild clean -project CITest.xcodeproj -scheme CITest | xcpretty
- xcodebuild test -project CITest.xcodeproj -scheme CITest -destination 'platform=iOS Simulator,name=iPhone 13,OS=15.5' | xcpretty -s
tags:
- mac-intel-latest
-destination
オプションの指定については次の記事を参照してください。

(6) Commit changes
をクリックする。
テスト
作成したテストコードをリポジトリにプッシュします。必ず失敗するテストなので、しばらくしてジョブが失敗し、エラー通知のメールが来ます。
プロジェクトのCI/CD
のPipelines
を開きます。失敗したジョブが表示されるので、failed
をクリックします。

Failed Jobs
タブを開きます。予定通りテスト失敗でエラーになっている場合は、次のように失敗したテストのテストケース(メソッド)名が出力されます。
2022-06-27 18:59:30.903 xcodebuild[18902:109049] [MT] IDETestOperationsObserverDebug: 0.000 sec, +0.000 sec -- start
2022-06-27 18:59:30.903 xcodebuild[18902:109049] [MT] IDETestOperationsObserverDebug: 104.154 sec, +104.154 sec -- end
Failing tests:
CITestTests:
CITestTests.testExample()
** TEST FAILED **
ERROR: Job failed: exit status 1
それ以外のエラーが出ている場合は、ログの内容を見て、設定などを見直してください。
UIテスティングについて
ここではXCTestを使ったユニットテストしか行っていませんが、UIテスティングについても変わりません。
XcodeのプロジェクトにUIテスティングのテストパッケージが入っていて、スキームのテストプランに登録されていれば、Xcodeから手動でテストするときと同じように、UIテストも自動的に実行されます。
トラブルシューティング
私が設定したときに遭遇したエラーと対応方法を掲載します。
ユーザーがログインしているときしか動かない
XCTestはログイン中のカレントユーザーが動かす必要があります。そのため、Runnerを動かすMacはログイン中になっている必要があります。
マシンを再起動したとき
公式の手順に従ってインストールすると、サービスとして登録されるので、マシンを再起動したときも、ログインさえすれば、Runnerが起動します。
状態がpending
のまま
状態がpending
のままで、パイプラインのbuild_project
を見ると、タグに対応したRunnerが存在しないというエラーが出ている。
このケースの場合は、次のような原因が考えられます。
tag
が間違っている。Shared Runner
を使おうとしているが、プロジェクトでShared Runner
が有効になっていない。- Mac上のRunnerがユーザーモードで動作していない。
2はこのページの「Shared Runnerを有効化する」を参照してください。
3は私がはまりました。Runnerを登録するときに、GitLabが出力したコマンドラインはsudo
が付いていて、そのまま実行すると、ユーザーモードでRunnerが動かないので、XCTestも動作しません。
シミュレータ名やOSバージョンが間違っている
この場合、build_project
のログの中に次のようなエラーが出力されていて、使用可能なシミュレータとOSの組み合わせが列挙されています。
xcodebuild: error: Unable to find a destination matching the provided destination specifier:
.gitlab-ci.yml
ファイル内で指定する値を適切な値に修正しましょう。
プロジェクトのCI/CD
のEditor
を開くと、.gitlab-ci.yml
ファイルをWebブラウザ内で編集してコミットできます。
シミュレータ名やOSバージョンの指定方法については、次の記事を参照してください。
