UI Automator テスト フレームワークには、ユーザーアプリとシステムアプリでインタラクションを実行する UI テストを作成するための API のセットが用意されています。
この方法を使用すると、テストをより簡潔で読みやすく、堅牢にすることができます。この API は開発中であるため、UI Automator を使用した新しい開発にはこの API を使用することを 強くおすすめします。従来の API のガイダンスもご利用いただけます。最新の UI Automator テストの概要
UI Automator 2.4 では、Android 用の UI テストの作成を簡素化する、Kotlin に適した合理的なドメイン固有 言語(DSL)が導入されています。この新しい API サーフェスは、述語ベースの要素検索とアプリの状態の明示的な制御に重点を置いています。この API を使用すると、保守性と信頼性の高い自動テストを作成できます。
UI Automator を使用すると、アプリのプロセス外からアプリをテストできます。これにより、縮小を適用したリリース バージョンをテストできます。 UI Automator も、Macrobenchmark テストの作成に 役立ちます。
最新の方法の主な機能は次のとおりです。
- よりクリーンで表現力豊かなテスト
コードを実現する専用の
uiAutomatorテスト スコープ。 - 明確な述語を使用して UI
要素を検索する
onElement、onElements、onElementOrNullなどのメソッド。 - 条件付き要素の組み込み待機メカニズム
onElement*(timeoutMs: Long = 10000) waitForStableやwaitForAppToBeVisibleなどの明示的なアプリの状態管理。- マルチウィンドウ テスト シナリオでのユーザー補助ウィンドウ ノードとの直接的なインタラクション。
- ビジュアル テスト
とデバッグのための組み込みのスクリーンショット機能と
ResultsReporter。
プロジェクトをセットアップする
最新の UI Automator API の使用を開始するには、プロジェクトの
build.gradle.kts ファイルを更新して、最新の依存関係を含めます。
Kotlin
dependencies {
...
androidTestImplementation("androidx.test.uiautomator:uiautomator:2.4.0-alpha05")
}
Groovy
dependencies {
...
androidTestImplementation "androidx.test.uiautomator:uiautomator:2.4.0-alpha05"
}
コア API のコンセプト
以降のセクションでは、最新の UI Automator API のコアコンセプトについて説明します。
uiAutomator テスト スコープ
uiAutomator { ... }
ブロック内で、すべての新しい UI Automator API にアクセスします。この関数は、テスト オペレーションに簡潔でタイプセーフな環境を提供する UiAutomatorTestScope を作成します。
uiAutomator {
// All your UI Automator actions go here
startApp("com.example.targetapp")
onElement { textAsString() == "Hello, World!" }.click()
}
UI 要素を検索する
述語を使用して UI Automator API を使用して、UI 要素を見つけます。これらの述語 を使用すると、テキスト、選択状態またはフォーカス状態 、コンテンツの説明などのプロパティの条件を定義できます。
onElement { predicate }: デフォルトのタイムアウト内で 述語に一致する最初の UI 要素を返します。一致する要素が見つからない場合、この関数は例外をスローします。// Find a button with the text "Submit" and click it onElement { textAsString() == "Submit" }.click() // Find a UI element by its resource ID onElement { viewIdResourceName == "my_button_id" }.click() // Allow a permission request watchFor(PermissionDialog) { clickAllow() }onElementOrNull { predicate }:onElementと似ていますが、タイムアウト内に一致する要素が見つからない場合はnullを返します。例外はスローされません。このメソッドは、省略可能な要素に使用します。val optionalButton = onElementOrNull { textAsString() == "Skip" } optionalButton?.click() // Click only if the button existsonElements { predicate }: 少なくとも 1 つの UI 要素が指定された述語に一致するまで待機し、一致するすべての UI 要素のリストを返します。// Get all items in a list Ui element val listItems = onElements { className == "android.widget.TextView" && isClickable } listItems.forEach { it.click() }
onElement 呼び出しを使用する際のヒントをいくつかご紹介します。
ネストされた要素の
onElement呼び出しをチェーンする:onElement呼び出しをチェーンして、親子階層に従って他の要素内の要素を見つけることができます。// Find a parent Ui element with ID "first", then its child with ID "second", // then its grandchild with ID "third", and click it. onElement { viewIdResourceName == "first" } .onElement { viewIdResourceName == "second" } .onElement { viewIdResourceName == "third" } .click()onElement*関数のタイムアウトを、 ミリ秒を表す値を渡して指定します。// Find a Ui element with a zero timeout (instant check) onElement(0) { viewIdResourceName == "something" }.click() // Find a Ui element with a custom timeout of 10 seconds onElement(10_000) { textAsString() == "Long loading text" }.click()
UI 要素を操作する
クリックをシミュレートするか、編集可能な フィールドにテキストを設定して、UI 要素を操作します。
// Click a Ui element
onElement { textAsString() == "Tap Me" }.click()
// Set text in an editable field
onElement { className == "android.widget.EditText" }.setText("My input text")
// Perform a long click
onElement { contentDescription == "Context Menu" }.longClick()
アプリの状態とウォッチャーを処理する
アプリのライフサイクルを管理し、テスト中に表示される可能性のある予期しない UI 要素を 処理します。
アプリのライフサイクル管理
API には、テスト対象のアプリの状態を制御する方法が用意されています。
// Start a specific app by package name. Used for benchmarking and other
// self-instrumenting tests.
startApp("com.example.targetapp")
// Start a specific activity within the target app
startActivity(SomeActivity::class.java)
// Start an intent
startIntent(myIntent)
// Clear the app's data (resets it to a fresh state)
clearAppData("com.example.targetapp")
予期しない UI を処理する
watchFor API を使用すると、テストフロー中に表示される可能性のある権限ダイアログなどの予期しない UI 要素のハンドラを定義できます。内部ウォッチャー メカニズムを使用しますが、柔軟性が向上します。
import androidx.test.uiautomator.PermissionDialog
@Test
fun myTestWithPermissionHandling() = uiAutomator {
startActivity(MainActivity::class.java)
// Register a watcher to click "Allow" if a permission dialog appears
watchFor(PermissionDialog) { clickAllow() }
// Your test steps that might trigger a permission dialog
onElement { textAsString() == "Request Permissions" }.click()
// Example: You can register a different watcher later if needed
clearAppData("com.example.targetapp")
// Now deny permissions
startApp("com.example.targetapp")
watchFor(PermissionDialog) { clickDeny() }
onElement { textAsString() == "Request Permissions" }.click()
}
PermissionDialog は ScopedWatcher<T> の一例です。ここで、T は
オブジェクトです。これは watchFor のブロックにスコープとして渡されます。このパターンに基づいてカスタム
ウォッチャーを作成できます。
アプリの可視性と安定性を待機する
要素が表示されるか安定するまでテストで待機する必要がある場合があります。 UI Automator には、この処理に役立つ API がいくつか用意されています。
waitForAppToBeVisible("com.example.targetapp") は、指定されたパッケージ名の UI 要素がカスタマイズ可能なタイムアウト内に画面に表示されるまで待機します。
// Wait for the app to be visible after launching it
startApp("com.example.targetapp")
waitForAppToBeVisible("com.example.targetapp")
waitForStable() API を使用して、アプリの UI が安定していると見なされることを確認してから操作します
。
// Wait for the entire active window to become stable
activeWindow().waitForStable()
// Wait for a specific Ui element to become stable (e.g., after a loading animation)
onElement { viewIdResourceName == "my_loading_indicator" }.waitForStable()
Macrobenchmark とベースライン プロファイルに UI Automator を使用する
UI Automator は、Jetpack Macrobenchmark とベースライン プロファイルの生成に使用します。これは、アプリを操作してエンドユーザーの視点からパフォーマンスを測定する信頼性の高い方法を提供するためです。
Macrobenchmark は UI Automator API を使用して UI を駆動し、インタラクションを測定します。
たとえば、起動ベンチマークでは、onElement を使用して UI
コンテンツが完全に読み込まれたタイミングを検出し、完全表示までの時間
(TTFD)を測定できます。ジャンクベンチマークでは、UI Automator API を使用してリストをスクロールするか
アニメーションを実行してフレーム タイミングを測定します。startActivity() や
startIntent() などの関数は、測定を開始する前に
アプリを正しい状態にする場合に便利です。
ベースライン プロファイルを生成するときは、アプリの重要なユーザー
ジャーニー(CUJ)を自動化して、事前コンパイルが必要なクラスとメソッドを記録します。UI
Automator は、これらの自動化スクリプトを作成するのに最適なツールです。最新の
DSL の述語ベースの要素検索と組み込みの待機メカニズム(onElement)
により、他の方法と比較して、より堅牢で決定論的なテスト実行が可能になります。
この安定性により、不安定さが軽減され、生成されたベースライン プロファイル
に、最も重要なユーザー
フロー中に実行されたコードパスが正確に反映されます。
高度な機能
次の機能は、より複雑なテスト シナリオで役立ちます。
複数のウィンドウを操作する
UI Automator API を使用すると、UI 要素を直接操作して検査できます。これは、ピクチャー イン ピクチャー(PiP)モードや分割画面レイアウトなど、複数のウィンドウを使用するシナリオで特に便利です。
// Find the first window that is in Picture-in-Picture mode
val pipWindow = windows()
.first { it.isInPictureInPictureMode == true }
// Now you can interact with elements within that specific window
pipWindow.onElement { textAsString() == "Play" }.click()
スクリーンショットとビジュアル アサーション
テスト内で画面全体、特定のウィンドウ、または 個々の UI 要素のスクリーンショットを直接キャプチャします。これは、ビジュアル 回帰テストとデバッグに役立ちます。
uiautomator {
// Take a screenshot of the entire active window
val fullScreenBitmap: Bitmap = activeWindow().takeScreenshot()
fullScreenBitmap.saveToFile(File("/sdcard/Download/full_screen.png"))
// Take a screenshot of a specific UI element (e.g., a button)
val buttonBitmap: Bitmap = onElement { viewIdResourceName == "my_button" }.takeScreenshot()
buttonBitmap.saveToFile(File("/sdcard/Download/my_button_screenshot.png"))
// Example: Take a screenshot of a PiP window
val pipWindowScreenshot = windows()
.first { it.isInPictureInPictureMode == true }
.takeScreenshot()
pipWindowScreenshot.saveToFile(File("/sdcard/Download/pip_screenshot.png"))
}
Bitmap の saveToFile 拡張関数を使用すると、キャプチャした
画像を指定したパスに簡単に保存できます。
デバッグに ResultsReporter を使用する
ResultsReporter を使用すると、スクリーンショットなどのテスト アーティファクトを Android Studio のテスト結果に直接関連付けて、検査とデバッグを容易にできます。
uiAutomator {
startApp("com.example.targetapp")
val reporter = ResultsReporter("MyTestArtifacts") // Name for this set of results
val file = reporter.addNewFile(
filename = "my_screenshot",
title = "Accessible button image" // Title that appears in Android Studio test results
)
// Take a screenshot of an element and save it using the reporter
onElement { textAsString() == "Accessible button" }
.takeScreenshot()
.saveToFile(file)
// Report the artifacts to instrumentation, making them visible in Android Studio
reporter.reportToInstrumentation()
}
古いバージョンの UI Automator から移行する
古い API サーフェスで作成された既存の UI Automator テストがある場合は、次の 表を参考にして最新の方法に移行してください。
| アクション タイプ | 古い UI Automator メソッド | 新しい UI Automator メソッド |
|---|---|---|
| エントリ ポイント | UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) |
テストロジックを uiAutomator { ... } スコープでラップします。 |
| UI 要素を検索する | device.findObject(By.res("com.example.app:id/my_button")) |
onElement { viewIdResourceName == "my\_button" } |
| UI 要素を検索する | device.findObject(By.text("Click Me")) |
onElement { textAsString() == "Click Me" } |
| アイドル状態の UI を待機する | device.waitForIdle() |
onElement の組み込みタイムアウト メカニズムを使用することをおすすめします。それ以外の場合は、activeWindow().waitForStable() を使用します。 |
| 子要素を検索する | 手動でネストされた findObject 呼び出し |
onElement().onElement() のチェーン |
| 権限ダイアログを処理する | UiAutomator.registerWatcher() |
watchFor(PermissionDialog) |