Macrobenchmark からアプリを制御する

ほとんどの Android UI テストとは異なり、Macrobenchmark テストはアプリ自体とは別個のプロセスで実行されます。これはアプリプロセスの停止や DEX バイトコードからマシンコードへのコンパイルなどを行うために必要です。

UIAutomator ライブラリか、テストプロセスからターゲット アプリを制御できるその他のメカニズムを使用して、アプリの状態を変更できます。Compose 要素を UI Automator に公開するには、Modifier.testTag を使用します。

次の例では、testTag を使用した LazyColumn を使用しています。

@Composable
fun ProductListScreen() {
    LazyColumn(
        modifier = Modifier
            .fillMaxSize()
            .testTag("my_lazy_column")    ) {
        items(100) { index ->
            ProductItem(index)
        }
    }
}

テストでは、testTag を使用して LazyColumn を見つけ、フリングします。

@Test
fun scrollList() {
    benchmarkRule.measureRepeated(
        packageName = "com.example.myapp",
        metrics = listOf(FrameTimingMetric()),
        iterations = 5,
        setupBlock = {
            uiAutomator {
                pressHome()
                startApp("com.example.myapp")
            }
        }
    ) {
        uiAutomator {
            // Find the Composable using its testTag mapped as a viewIdResourceName
            val lazyColumn = onElement { viewIdResourceName == "my_lazy_column" }

            // Fling the Compose list down
            repeat(3) {
                lazyColumn.fling(Direction.DOWN)
            }
        }
    }
}

ベンチマークで UI をスクロールする必要はありません。代わりにアニメーションなどを実行できます。また、特に UI Automator を使用する必要もありません。フレームが生成されている限り、パフォーマンス指標が収集されます。

アプリの起動時にすぐに表示されない特定の画面(Jetpack Navigation グラフ内の詳細画面や購入手続きページなど)をベンチマークしたい場合があります。

Macrobenchmark はプロセス外で実行されるため、NavController を直接操作して画面を切り替えることはできません。代わりに、ベンチマークはユーザーがアプリのその部分に移動する様子をシミュレートする必要があります。

setupBlock を使用して、オンボーディング フローやメニューボタンのクリックなどの準備手順を処理します。これにより、measureBlock は対象画面のパフォーマンス指標のみをキャプチャします。

@Test
fun deepScreenScrollList() {
    benchmarkRule.measureRepeated(
        packageName = "com.example.myapp",
        metrics = listOf(FrameTimingMetric()),
        iterations = 5,
        setupBlock = {
            uiAutomator {
                // 1. Start the app on the home screen
                startApp("com.example.myapp")

                // 2. Navigate to the internal screen by clicking a Compose component
                // (e.g., a card that opens the target list view)
                val settingsButton = onElement { viewIdResourceName == "go_to_list_button" }
                settingsButton.click()

                // 3. Wait until the target screen settles and is fully rendered
                waitForStableInActiveWindow()
            }
        }
    ) {
        uiAutomator {
            // The actual benchmark measurement starts here on the target screen
            val lazyColumn = onElement { viewIdResourceName == "my_lazy_column" }
            lazyColumn.fling(Direction.DOWN)
        }
    }
}

参考情報

テストの詳細については、次のリソースをご覧ください。

ドキュメント

コンテンツの閲覧