Gunosy Tech Blog

Gunosy Tech Blogは株式会社Gunosyのエンジニアが知見を共有する技術ブログです。

Android Macrobenchmark テストの導入

こんにちは。Android アプリ開発担当の nagayama(@nagayan_dev)です。
今回私が担当している「auサービスToday」で Macrobenchmark ライブラリを用いたテストを導入したため、その内容をお伝えします。



Benchmark とは

Benchmark とは、アプリのパフォーマンスを検査およびモニタリングするための手段です。Benchmark を定期的に実施することで、開発で想定していないパフォーマンス劣化のキャッチアップができたりと、メリットが大きいテスト手法です。

Android の Benchmark ライブラリは、 Macrobenchmark と Microbenchmark の 2 種類があります。

Macrobenchmark ライブラリでは、起動・UIの操作・アニメーションのようなユーザーが体感する部分のパフォーマンス検査を実施することができます。

Microbenchmark ライブラリでは、Kotlin や Java のコードパフォーマンス検査ができます。スクロール時の処理やデータ変換といった、繰り返し使用されるコードブロックの検査に用いられることが多いです。

developer.android.com

対応方針

今回は Macrobenchmark ライブラリを用いたテストの導入を行います。
アプリの起動時間を改善するにあたり、定期的に起動時間を測定する必要がありました。Macrobenchmark ライブラリを用いた起動時間テストであれば、容易にその環境を作成することが可能です。また後日対応予定である Baseline Profiles でも、実際にパフォーマンス改善がされたかどうかを確認するために Macrobenchmark のテスト実行を行う必要がありました。


実装

Android Developers に Macrobenchmark テストの導入方法について記載されています。

developer.android.com

こちらを元に導入をすすめていきます。

compileSDKバージョンのアップデート

compileSDKバージョンの対象が 34 以上であったため、バージョンを設定します

android {
    compileSdk 34

macrobenchmark モジュールを作成

他のソースコードと別管理をするため Macrobenchmark 用のモジュール を作成します。今回のテストはこのモジュール内で完結するように作成します。

Android のプロジェクトから [New] > [Module] から作成します。Templates の中に Benchmark があるため、それを選択するとこの後に設定するものが全て設定済みな状態になってくれます。

ライブラリ追加

今回は下記のライブラリを追加しました。

dependencies {
  implementation "androidx.benchmark:benchmark-macro-junit4:$benchmark_version"
  implementation "androidx.test.uiautomator:uiautomator:$uiautomator_version"
}

Gradle ファイルの設定

まず、プラグインを com.android.library から com.android.test に変更します。

plugins {
    id 'com.android.test'

今回は独立したテスト実行環境として管理しうるため、benchmark という buildTypes を追加します。

またテスト対象となるモジュール等、必要な設定を追記します。

android {
  buildTypes {
    benchmark {
      debuggable = true
      signingConfig = debug.signingConfig
      matchingFallbacks = ["release"]
    }
  }
  targetProjectPath = ":app"
  experimentalProperties["android.experimental.self-instrumenting"] = true

テストクラスを作成

Macrobenchmark テストを実行するテストクラスを作成します。今回は下記のようにアプリ起動をするだけのテストになります。

@RunWith(AndroidJUnit4::class)
class ExampleStartupBenchmark {
    @get:Rule
    val benchmarkRule = MacrobenchmarkRule()

    @Test
    fun startup() = benchmarkRule.measureRepeated(
            packageName = PACKAGE_NAME,
            metrics = listOf(StartupTimingMetric()),
            iterations = 5,
            startupMode = StartupMode.COLD
    ) {
        pressHome()
        startActivityAndWait()
    }
}

テスト対象モジュールの AndroidManifest に profileable タグを追加

Benchmark を実行するには、対象の AndroidManifest に profileable タグを設定する必要があります。

また buildType が benchmark 時のみに付与したいため [テスト対象のモジュール] / src / benchmark に AndroidManifest を作成し、下記の profileable タグを設定しました。

 <application ... >
    <profileable
        android:shell="true"
        tools:targetApi="p" />
</application>

実装は以上です。


実行結果

テストを実行していきます。 実行すると下記のような結果が得られます。timeToInitialDisplayMs には起動時間の 最小値・中央値・最大値 が出力されました。

これでアプリの起動時間をMacrobenchmark テストを用いて、測定できるようになりました。


まとめ

Macrobenchmark テストの導入実装についてお伝えしました。今回は本当に導入部分のみで、こちらを用いて定期的なパフォーマンス監視体制を整えたり、このテストコードを用いて Baseline Profiles のパフォーマンス確認を行なっていきたいと思います。