Unyablog.

のにれんのブログ

travis で Android (Kotlin 付き) のテストをするときにしたことのメモ

自分の作ってるアプリにテスト書いてtravisでやってくれるようにした話です。

テスト

長らくテスト全く書かずにしてきたのですがいい加減そろそろテスト書かないとなあと思ったのでテストをシュババっと書きました。*1

とりあえず gradle にシュッとそれっぽい依存を書いて

そして kotlin でパパっとテストを書きました。*2

kotlin でテストできるか不安でしたが java でちょっとだけ書いてそれを convert したものを参考に書いたら普通に動いてくれたので安心。

ということでとりあえずテストは完成。実機でも無事通りました。

travis の前準備(キーの暗号化)

今までは secret key とかは key.xml 的な秘蔵のxmlに保存していましたが、 travisコンパイルできるようにする必要があるためなんとかして travis にキーを伝える必要があります。

ここで travis のキー暗号化機能を使います。

Encryption keys - Travis CI

これを使えば暗号化されたキーを置くと、travis がいい感じに展開してくれて環境変数にキーなどを export してくれます。

それを gradle で読むようにして、キーを resource(@string) 経由ではなく BuildConfig 経由で直接埋め込んでしまうという作戦でこうなりました。

def FLICKR_KEY
def TWITTER_KEY
...

def file = project.file('key.properties')
if (file.exists()) {
    def properties = new Properties()
    properties.load(file.newDataInputStream())
    FLICKR_KEY = properties.get("FLICKR_KEY")
    TWITTER_KEY = properties.get("TWITTER_KEY")
    ...
} else {
    FLICKR_KEY = System.getenv("FLICKR_KEY")
    TWITTER_KEY = System.getenv("TWITTER_KEY")
    ...
}

buildConfigField "String", "FLICKR_KEY", "\"${FLICKR_KEY}\""
buildConfigField "String", "TWITTER_KEY", "\"${TWITTER_KEY}\""
...

ローカルでは key.properties の値を読むようにし、 travis では環境変数を読むようにしました。

key.properties の存在を確認し、存在すればプロパティとして読み込み〜〜という動作になっています。

ちなみに key.properties

FLICKR_KEY = xxxxxxxxxxxxxxx
TWITTER_KEY = xxxxxxxxxxxx
~~~~

といった感じです。

そして travis 用の暗号化されたキーを生成します。

その前にレポジトリを travis に連携させる必要があるのでgithub経由でログインして連携させ、

$ sudo gem install travis

して、.travis.ymltouch しておけば、

$ travis encrypt <環境変数名>=<値> --add

すると勝手に .travis.yml に追加してくれます。便利!

travis

次は .travis.ymlAndroid 用の設定をゴリゴリ書きます。

Building an Android Project (beta) - Travis CI

が公式のガイド*3です。

実装は

等を参考にして書きました。

# .travis.yml
language: android
jdk: oraclejdk7 # なくてもいいかも?
sudo: false # 多少早くなるらいしい
env:
  global:
  - GRADLE_OPTS="-Xmx512m -XX:MaxPermSize=512m"
  - ADB_INSTALL_TIMEOUT=10
  - secure: <SECRET-KEY1>
  - secure: <SECRET-KEY2>

android:
  components:
    - android-23
    - android-22
    - build-tools-23.0.1
    - build-tools-22.0.1
    - extra-android-support
    - extra-android-m2repository
    - extra-google-m2repository
    - sys-img-armeabi-v7a-android-19

# Emulator Management: Create, Start and Wait
before_script:
  - echo no | android create avd --force -n test -t android-19 --abi armeabi-v7a
  - emulator -avd test -no-skin -no-audio -no-window &
  - android-wait-for-emulator
  - adb shell input keyevent 82 &

script:
    - ./gradlew --info clean lint :app:connectedAndroidTest

kotlin でしたが後述のヒープサイズ以外は特別な設定は必要としませんでした。さすが kotlin。

つまづきどころ

  • ./gradlew: Permission denied

これは gradlewパーミッションが正しく設定されてないことによるエラーです。chmod +x gradlew すると直りました。

  • > failed to find target with hash string 'android-22' in: /usr/local/android-sdk

これはプロジェクト内に直接 volley を submodule で組み込んでおり、 volley は Android SDK 22 でビルドする必要があるために起きたエラーです。android-22components に加えましょう。

  • > failed to find Build Tools revision 22.0.1

これも↑とほぼ同じエラーですね。 build-tools-22.0.1 を加えましょう。

  • * What went wrong: PermGen space

メモリが足りていないことが原因でした。 kotlin とか sbt とか使うとこのエラーがよく出るみたいです。

- GRADLE_OPTS="-Xmx512m -XX:MaxPermSize=512m"

envglobal に加えるとヒープが大きくなってビルドできました。この値は大きすぎると travis の制限に引っかかるようなので 512 か 1024 程度でいいと思います。

  • Unable to upload some APKs ShellCommandUnresponsiveException

インストール時間の制限に引っかかった*4?と思って

- ADB_INSTALL_TIMEOUT=10

envglobal に入れたら直りました。*5

  • Timeout (360 seconds) reached; failed to start emulator

emulator がいつまでも starting だったというエラー。エミュレータに andorid-23 を使うとそんなエラーになったのでまだ不安定なのかもしれません。いい感じにfixする方法も特に見つからず*6、仕方ないので android-22 にすると出なくなりました。

その他

  • エミュレータを起動するのにまず時間がかかります。そしてビルドするのにも clean してますし毎回レポジトリから持ってきてるので非常に時間がかかります。*7
  • 同時に複数のバージョンでテストする

先ほど貼った GitHub のレポジトリにある通り、

matrix:
  - ANDROID_TARGET=android-22
  - ANDROID_TARGET=android-19
  - ANDROID_TARGET=android-17
  - ANDROID_TARGET=android-15

env に設定し、

- echo no | android create avd --force -n test -t $ANDROID_TARGET --abi armeabi-v7a

とすることで、複数の環境変数で並列テストしてくれます。もちろん、対応したバージョンの sys-img を読み込む必要があります。

テストに通ったのが GitHub に反映された様子

参考になったサイト

Kotlin でテスト。

BuildConfig について。

BuildConfig について。

travisandroid を用いる

sbt の travis マニュアル

関連記事

*1:軽いテストでActivity関係の闇なテストは行っていません

*2:expected と actual の順番がミスって逆になっています http://qiita.com/deflis/items/645451d7fd85932d1134

*3:実は少し古くて、最新のバージョンのビルドツール使えるし、androidも使えます。ただ最新の andorid は後述の通りちょっと不安定

*4:http://stackoverflow.com/questions/28949722/android-tests-fail-on-travis-with-shellcommandunresponsiveexception

*5:ですが今見たらその時エラーが出てたビルドも後から見るとインストールに成功してて、よくわからないです… まあとりあえずオプションを付ければ直る?

*6:タイムアウト伸ばすだけなら wait_for_emulator コマンドを内部のを使わずに、タイムアウト時間を fix したものを curl するなりして持ってきてからそれを実行すればいい話ではあるのですが、他のエミュレータは6分もかからないので異常な気がする、けどそんなもんな気もする

*7:travis やたら firefox では js 固まって重いのなんとかならないんですかね...