🤖

BitriseでAndroidライブラリモジュール(AAR)のAndroidTestを実行する

2023/01/05に公開

ニッチな需要ではあるが、ライブラリをSDKとして社外に渡す機会があり、BitriseではAndroidライブラリ(AAR)でAndroiTestを実行することができず困っていた。

エラーログと闘った結果、Issueコメントにあったワークアラウンド対応で実行することができたのでメモしておく。

先に結論

Bitriseはライブラリモジュールの【Virtual Device Testing】を想定していないので、【Virtual Device Testing】の【App Path】には適当なダミーAPKを指定する

参考URL: https://github.com/bitrise-steplib/steps-virtual-device-testing-for-android/issues/26#issuecomment-927696725

経緯と詳細

前提条件

  • ライブラリモジュールだけ開発しており、アプリケーションモジュールはCI/CDの対象にしてない
  • Android OSの機能に依存しており、androidTest配下でしかUnitTestが実行できない(血涙)

解決までの流れ

下記のようなアプリモジュールとライブラリモジュールのシンプルプロジェクトがあったとする。

BitriseAarAndroidTest
├ :app
└ :mylibrary
  ├ androidTest
  │ └ LibrarySampleTest
  └ main
    └ LibrarySample

LibrarySampleには不届き者が追加したデバックコードが含まれており、AndroidTestでしかUnitTestを実行できない。

LibrarySample
import android.os.SystemClock

object LibrarySample {
    fun hello(): String {
        // FIXME 消して
        val start = SystemClock.elapsedRealtime()
        val end = SystemClock.elapsedRealtime()
        println("time: ${end - start}")

        return "Hello"
    }
}

LibrarySampleTestの中身は至って単純。

LibrarySampleTest
class LibrarySampleTest {
    @Test
    fun testHello() {
        assert(LibrarySample.hello() == "Hello")
    }
}

hello()がAndroid OSの機能を使っていなければどれだけ良かったことか。と思うが、AndroidStudio上では無論、問題なくテストが通る。通ってしまう。

BitriseでAARのInstrumentationTest

さて、BitriseでAndroidプロジェクトを追加すると、デフォルトで下記のprimary WorkFlowが作成される

bitrise.yml
  primary:
    description: |
      Runs tests.

      Next steps:
      - Check out [Getting started with Android apps](https://devcenter.bitrise.io/en/getting-started/getting-started-with-android-apps.html).
    steps:
    - activate-ssh-key@4: {}
    - git-clone@6: {}
    - cache-pull@2: {}
    - install-missing-android-tools@3:
        inputs:
        - gradlew_path: "$PROJECT_LOCATION/gradlew"
    - android-unit-test@1:
        inputs:
        - project_location: "$PROJECT_LOCATION"
        - variant: "$VARIANT"
    - cache-push@2: {}
    - deploy-to-bitrise-io@2: {}

これだと通常のUnitTestしか実行されず、今回作成したLibrarySampleTestは実行されないので、仮想デバイスによるInstrumentationTestを追加する。

仮想デバイスでテストするにはAndroidTest実行用のapkを作成する必要があるので、android-build-for-ui-testingも追加しておく。

bitrise.yml
    - android-build-for-ui-testing@0:
        inputs:
        - variant: debug
        - module: mylibrary
    - virtual-device-testing-for-android@1:
        inputs:
        - test_devices: NexusLowRes,30,en,portrait
        - test_type: instrumentation

GUIだとこんな感じ。

これで.aarが生成されて、仮想デバイスでテストしてくれるはず。

実行(1敗)

BUILD SUCCESSFUL in 35s
54 actionable tasks: 40 executed, 14 up-to-date
APKs found after the build:
1. /bitrise/src/mylibrary/build/outputs/apk/androidTest/debug/mylibrary-debug-androidTest.apk
Export APKs:
  Export [ mylibrary-debug-androidTest.apk => $BITRISE_DEPLOY_DIR/mylibrary-debug-androidTest.apk ]
Could not find the exported app APK
|                                                                              |
+---+---------------------------------------------------------------+----------+
| x | Android Build for UI Testing                                  | 37.79 sec |
+---+---------------------------------------------------------------+----------+
| Issue tracker: https://github.com/bitrise-steplib/bitrise-step-android-bu... |
| Source: https://github.com/bitrise-steplib/bitrise-step-android-build-for... |
+---+---------------------------------------------------------------+----------+

しかし、 BUILD SUCCESSFUL と勝利宣言をされているにもかかわらず Could not find the exported app APK とFailure扱いになる。後続の【Virtual Device Testing】はスキップ扱いとなる。

Virtual Device Testingを強制的に実行しても良いが、InstrumentationTestの実行対象は$BITRISE_APK_PATHなので、拾ってくれるかも怪しい。

し、どの道【Android Build For UI Testing】がコケてるので何とかしたい。

Gradleで無理やりAndroidTest用のAPKを作る

AndroidStudioでは下記のコマンドでライブラリモジュールでもAndroidTest用のAPKを作成できる

./gradlew :mylibrary:assembleDebugAndroidTest

ので、Bitriseから上記のコマンドを実行できるよう、【Android Build For UI Testing】を消して【Gradle Runner】を追加する。

bitrise.yml
    - gradle-runner@2:
        inputs:
        - gradlew_path: "./gradlew"
        - gradle_task: ":mylibrary:assembleDebugAndroidTest"

これで実行すると、

Collecting cache:
Move APK and AAB files...
No file name matched app filters
Copying mylibrary/build/outputs/apk/androidTest/debug/mylibrary-debug-androidTest.apk --> /bitrise/deploy/mylibrary-debug-androidTest.apk
The apk path is now available in the Environment Variable: $BITRISE_TEST_APK_PATH (value: /bitrise/deploy/mylibrary-debug-androidTest.apk)
Move mapping files...
No mapping file matched the filters

AndroidTest用のAPKは$BITRISE_TEST_APK_PATHに紐づけられるとご丁寧に教えてくれるので、【Virtual Device Testing】を改修する。

bitrise.yml
    - virtual-device-testing-for-android@1:
        inputs:
        - app_path: "$BITRISE_TEST_APK_PATH"
        - test_devices: NexusLowRes,30,en,portrait
        - test_type: instrumentation

実行(2敗)

Failed to get test status, error: Failed to get test status: INVALID(TEST_SAME_AS_APP) (exit code: 1) と怒られる

どうも、下記2ヶ所のパスが被ってると怒られるらしい。

  • Virtual Device Testing > App Path
  • Virtual Device Testing > Instrumentation Test > Test APK Path

AARではAndroidTestでしかAPKを生成できないため、別のApp Pathを指定できない。困った。

適当なダミーAPKを渡す

調べたらIssueが立っており、ワークアラウンドが投稿されていた。

https://github.com/bitrise-steplib/steps-virtual-device-testing-for-android/issues/26#issuecomment-927696725

App Pathは要求されているだけでテスト対象じゃないっぽいので、適当なAPKをリポジトリに入れて渡せば良いらしい。

今回は:appのデバッグ版をビルドしてプロジェクト直下に置いてみた。

BitriseAarAndroidTest
├ :app
└ :mylibrary
│ ├ androidTest
│ │ └ LibrarySampleTest
│ └ main
│   └ LibrarySample
└ dummy.apk // ← NEW!!

【Virtual Device Testing】のapp_pathは直書きである。

bitrise.yml
    - virtual-device-testing-for-android@1:
        inputs:
        - app_path: "./dummy.apk"
        - test_devices: NexusLowRes,30,en,portrait
        - test_type: instrumentation

実行(1勝)

無事、 Success やったね!

Discussion