Androidプロジェクト用GitLab CI設定 ~自動テスト機能がある、アプリ開発体制をつくる! | from: about.gitlab.com

法律: IT 解説記事 Android GitLab CI フノス(訳者)

 Android開発環境に、きちんとしたコード判定システムを構築するワザをお教えします。


  コードはどうしても手打ちが多く、たかだか打ち間違いを探すために、膨大な時間を割いてしまうことがあります。
 とくに、Android開発に携わっている方は、「ビルドすらできない」とか、「原因不明のバグ」とかに悩まされた経験があるのではないでしょうか。
 まして、継続的インテグレーションを開発体制に取っている場合などは、凡ミスですべてを台無しされる事態が、頭痛の種というもの。

 アプリのコンパイルをさらに確実なものにするために、Gitへのマージの前にはテストをしておきたいものですね。
 

  そこで有効な対処法となるものは、なんと「GitLab CI」です。
 コンフィグファイル( .gitlab-ci.yml)次第で、ユニットテストや、機能テストを実施できるようになります。

 これをひとたび備え付けると、
 アプリケーションを試作し、ローカル環境でテストをしてから、公式に発表するという、安定したワークフローを構築できます。
 それも、テストは GitLab UIでほとんど完結できるものになるので、大変お手軽です。

 

  今回使ったサンプルアプリ

 まず、ここでは説明を分かりやすくするために「sample project」というAndroidアプリを作りました。
 これは単なる2つの数を”足し算”するだけという、ちょっとプログラムをかじっている人なら、コードに見当がついてしまうほど簡単なアプリケーションです。

 ただ、これからの説明のかなめである「どこをどうテストしているか」が、はっきり分かりやすくなりそうなので、これを例に出してみました。
 (写真1)今回のアプリ

 

  ユニットテスト

  ユニットテストは、アプリケーションの動作を確認するのに欠かせないテストです。
 アプリケーションにいくつも仕掛けられているそれぞれのユニットが、論理的に正しく、矛盾する部分がないかを確かめます。
 これの良さは、たくさんのコードを記述してしまったあとでも、どこまでさかのぼって訂正を入れれば良いかが分かりやすく教えてくれる所にあります。

 ユニットテストは、Java仮想マシン(JVM)で直接稼働できるシステムなので、わざわざAndroidデバイスで試す手間がかかりません。
 

  これからGitLab CIでユニットテストをする方法をお教えしますが、
 すでに別のユニットテスト・システムをお使いの場合は、競合を避けるために使用をひかえてください。

 今回のユニットテストでは、Robolectricを使っておりませんが、これは併用しても差し支えないでしょう。

 

  機能テスト

  機能テストは、「UIテスト」や「エミュレータテスト」とも呼ばれることがあります。
 ユニットテストでは満足に検査できない部分も、このテストでなら割り出せることがあります。

 たとえば、テスト対象のアプリに、複数のユーザーパスを与えてテストしようにも、ユニットテストはそのような細かい操作が不得意です。

 今回の機能テストでは、ユーザーが入力した数字にパスをつけて、「Calculate」ボタンを押したらどのような結果になるかを審査します。

 機能テストは実際のAndroidデバイスやエミュレータでテストしなくてはなりませんので、幾分も効率が落ちます。

  しかし、これには「アプリを起動したまま画面をロックした」ときなどに、どのようなバグが出るかなど、実際の使用に即したテストが可能なので、より精細なテスト結果を出すことができます。

 ただし今回は、デバイスで「画面ロック」がどう出るかを試験する程度にとどまらせていただきました。

 機能テストは以下のコードを基本として構成しています。
 最初の「@Before」とついているユニットは、それぞれのテストをする前に実施する動作を記しています。
 

======================
 @Before
 public void setup() {
   // 画面のロックを解除したとき
   UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
   try {
     device.wakeUp();
   } catch (RemoteException e) {
     e.printStackTrace();
   }

   // スクリーンをロックする、しないにかかわらず、実行する動作のフラグ
   final Activity activity = getActivityRule().getActivity();
   Runnable wakeUpDevice = new Runnable() {
     public void run() {
           activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
         WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
           WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
     }
   };

   activity.runOnUiThread(wakeUpDevice);
 }
======================

 さて、これでテストを作る前準備はおおよそ完了しました。
 
 

  GitLab CIの設定 

  これからCIを使って、「アプリをビルドして、ユニット/機能テストの両方ができる」環境を支度していきます。

 これから言う内容を「.gitlab-ci.yml」というファイルに設定して、プロジェクトのrootディレクトリに配置してください。

  さて、最初に。
 次の内容を「.gitlab-ci.yml」にコピー&ペーストしてください。
 この中に、ビルドもテストも設定されています。

 (原文はここでコードが表示されています。が、長い。なので、以下のリンクを参考にしてください。)

  こちらのページです。

  いや、もうこんだけ!これコピペするだけで十分だから!

 

  .gitlab-ci.yml解説

 
 Docker Imageを設定する
======================
 image: openjdk:8-jdk
======================
 これは、GitLab Runners (アプリのビルドを担当しているもの)に、使用する Docker image を指定するコマンドです。

 ここで Dockerのことよく知らない方に。
 厳密にいえばちょっと違うのかもしれないけど、Dockerは仮想OSをさらに独立化させたようなもののこと。(コンテナという。)
 使い心地は仮想OSとよく似てる。
 ただ、仮想マシンと違うのは、とにかく作りやすくて壊しやすいこと。その場限りのビルドやテストにはうってつけなわけだ。
 

  さて、話を戻しましょう。
 Docker image は( openjdk:8-jdk)と指定されています。
 openjdkとは、Debian OSでプリインストールされているJava開発環境のことで、Androidアプリを作る時にも使える環境です。
 そして、その下にはこの開発環境が認識できるようなコマンドが記されています。

 

  変数について

======================
variables:
  ANDROID_COMPILE_SDK: "25"
  ANDROID_BUILD_TOOLS: "24.0.0"
  ANDROID_SDK_TOOLS: "24.4.1"
======================
 ここで設定する変数は、「build.gradle」という設定ファイルに記載したものと同じものを載せなくちゃいけないので、適宜変わる場合もあるけど、一応解説。

 



 パッケージのインストール
======================
before_script
:
  - apt-get --quiet update --yes
 
- apt-get --quiet install --yes wget tar unzip lib32stdc++6 lib32z1
====================== 

 

  このコマンドをいれておくだけで、パッケージは常に最新のものにアップデートされるので、安心です。
 だけど、それ逆にいえば、「常に最新パッケージにしておいてほしいソフトは全部書いといた方がよい」という話だから、コンフィグファイルが長文化していくわけです。

 さらに、インストールしたいソフトのパッケージによっては、上にあるように「wget」、そしてこれから登場する「tarunzip」というコマンドが必要だったり、64ビットマシンで32ビットソフトを使う設定が必要だったりもします。

 Android SDKインストール(上の続き)

======================
- wget --quiet --output-document=android-sdk.tgz https://dl.google.com/android/android-sdk_r${ANDROID_SDK_TOOLS}-linux.tgz
- tar --extract --gzip --file=android-sdk.tgz
- echo y | android-sdk-linux/tools/android --silent update sdk --no-ui --all --filter android-${ANDROID_COMPILE_SDK}
- echo y | android-sdk-linux/tools/android --silent update sdk --no-ui --all --filter platform-tools
- echo y | android-sdk-linux/tools/android --silent update sdk --no-ui --all --filter build-tools-${ANDROID_BUILD_TOOLS}
- echo y | android-sdk-linux/tools/android --silent update sdk --no-ui --all --filter extra-android-m2repository
- echo y | android-sdk-linux/tools/android --silent update sdk --no-ui --all --filter extra-google-google_play_services
- echo y | android-sdk-linux/tools/android --silent update sdk --no-ui --all --filter extra-google-m2repository
======================
 このコマンド全体で、Android SDKツールを公式の通りにインストールします。
 バージョンの指定に、「ANDROID_SDK_TOOLS」という変数を使っています。
 全体の流れとしては、ツールのデータ圧縮をといたら、その下にたくさん続いている「android」コマンドでAndroid SDKパッケージをインストールしています。
 このようにして、アプリをビルドするのに必要な材料をそろえます。

 ですが、「before_script」には、まだ3行続きがあります。

 環境のセッティング

======================
- export ANDROID_HOME=$PWD/android-sdk-linux
- export PATH=$PATH:$PWD/android-sdk-linux/platform-tools/
- chmod +x ./gradlew
======================

 まず、3行の一番上に「ANDROID_HOME」という環境変数がありますが、これでSDKのロケーションを表しています。これがアプリをビルドする時に必須です。

 次に、インストールしたプラットフォームツールにパスを設けています。今回はパスの先をかなり正確に書きましたが、「adb」コマンドを使って短縮しても構いません。とくに、後からスクリプトを変更する可能性がある場合は、このコマンドを使った方が良いでしょう。

 最後に、「gradlew」に実行権を与えます。
 これがないと、ここに書いたスクリプトがきちんと実行されるかどうかが、すこし不確実になります。

 

  stagesを定義する
======================
stages:
  - build
  - test
======================
 複数のステージを使用する時には、あらかじめ「どのステージを使うか」を定義しておいた方が良いでしょう。

 ステージはjobをグループ分けする仕組みです。
 同じステージに置かれたjobは同時に動き出し、その全部が終わると、次のステージのjobが一斉に動き出します。

 今回の設定では、「build」ステージでアプリのコンパイルを、
 「test」ステージでユニット/機能テストを実施すると考えてください。


 

  ユニットテストを実行する
======================
unitTests:
  stage
: test
  script
:
   - ./gradlew test
======================
 ユニットテストにおいては、「unitTests」というjobを「test」ステージで実行する、という簡単な設定で十分です。

 

 機能テストを実行する

 

======================
functionalTests:
  stage: test
  script:
   - wget --quiet --output-document=android-wait-for-emulator https://raw.githubusercontent.com/travis-ci/travis-cookbooks/0f497eb71291b52a703143c5cd63a217c8766dc9/community-cookbooks/android-sdk/files/default/android-wait-for-emulator
  
- chmod +x android-wait-for-emulator
  
- echo y | android-sdk-linux/tools/android --silent update sdk --no-ui --all --filter sys-img-x86-google_apis-${ANDROID_COMPILE_SDK}
  
- echo no | android-sdk-linux/tools/android create avd -n test -t android-${ANDROID_COMPILE_SDK} --abi google_apis/x86
  
- android-sdk-linux/tools/emulator64-x86 -avd test -no-window -no-audio &
  
- ./android-wait-for-emulator
  
- adb shell input keyevent 82
  
- ./gradlew cAT
artifacts:
   paths
:
   - app/build/reports/androidTests/
======================

  問題はこちらのjobです。
 「functionalTests」というjob名、「test」ステージの指定の他、どのようにテストをするかも指定しなくてはなりません。

 「-」がついている行について大まかに説明します。

 まず、エミュレータを起動したら、すぐさまスクリプトをダウンロードさせます。

 それから、エミュレータにシステムのイメージをダウンロードします。

 次に、エミュレータがスクリプトをダウンロードするまで次の作業をまつコマンドを入れます。

 そして、「abd」コマンドで画面のロックを解除するシグナルを送って、
 「./gradlew cAT」でテストが開始されます。

 テストが終了すると、 「app/build/reports/androidTests/」というディレクトリに報告書が送られます。


 

  新しく作ったCIを使ってみる

  部分的に変更点があるかもしれませんが、基本はリンク先のファイルをコピペするだけで十分使えるはずです。
 「.gitlab-ci.yml」をrootディレクトリに配置して、変更をプッシュしましょう。
 ご自分のプロジェクトから「Pipelines」のタブを開いて、ビルドの様子を確認しましょう。
 さっき設定したテストの結果もここに表示されるはずです。

 (写真2)パイプライン・タブ

  ビルドが終わったら、出来上がったものをダウンロードできます。  

  (写真3)ビルド完了マーク

  (写真4)Buildsタブ

 (写真5)ダウンロードボタン

 

  おわりに

  さて、これで全ての説明が終了しました。
 これを参考にして、コンパイルとテストとを自動で果たす環境を作ってくださいね。
 できたアプリ(APK)にアクセスして、ダウンロードしてみても、そうそう問題は起こりません。
 

  恐ろしいミスも起こりづらいなら、アプリ開発も楽しくなるはず(^_-)-☆

  ゲスト著述家
 Greyson Parrelli
 Snap Inc所属のAndroidディベロッパー。現在はSnapchatの開発に携わっている。 過去には、YouTubeYahoo! WeatherYahoo! Mail のAndroid版アプリ開発にも携わっており、経験豊富。2017-11-04 19:10:38 / Hnoss
原文サイトを表示
[ 原文 ] https://about.gitlab.com/2016/11/30/setting-up-gitlab-ci-for-android-projects/
Creative Commons License この作品は、クリエイティブ・コモンズ・ライセンスの下でライセンスされています。
クリエイティブ・コモンズ・ライセンス