UI Automatorは、GoogleによるAndroidアプリケーションの自動UIテストフレームワークで、システムレベルで動作し、単一アプリを超えてインターフェース要素と対話できます。Espressoとは異なり、UI Automatorは特定のアプリケーションプロセスに結びつきません。システムダイアログ、通知シェードを開き、アプリケーション間を切り替えることができます。Google Android Developersによると、UI Automatorは標準のAccessibility Serviceを使用してデバイスのUIツリーにアクセスします。
主要項目
UI Automatorは、オペレーティングシステムレベルで動作するAndroidの機能UIテストのためのフレームワークです。デバイス画面の任意の要素にアクセスするためのAPIを提供し、それがどのアプリに属しているかに関係なく — システムステータスバー、権限ダイアログ、ホーム画面、サードパーティアプリを含みます。これにより、単一アプリを超えるシナリオのテストに不可欠です。
アーキテクチャ的には、UI AutomatorはAccessibility Serviceを使用します — TalkBack、Switch Access、その他のアクセシビリティツールが使用する同じサービスです。このサービスを通じて、フレームワークは現在の画面の完全なUIコンポーネントツリーを取得し、タップ、スワイプ、テキスト入力、長押しなどのアクションを実行できます。
UI AutomatorはAndroid 4.3(API 18)で初めて登場し、それ以来、クロスアプリケーションテストのためのGoogleの公式ツールとしてAndroid Testing Support Libraryの一部です。AndroidX Testでは、個別のアーティファクトandroidx.test.uiautomator:uiautomatorバージョン2.3.0(2024)として利用可能で、API 18以降のすべてのAndroidバージョンをサポートしています。
動作原理: UI Automatorは、現在の画面のアクセシビリティツリーをスキャンすることに基づいています。findObject(selector)メソッドが呼び出されると、フレームワークはView階層を走査し、UiSelector条件に一致する最初の要素を見つけ、UiObject — 実際のViewと対話するためのプロキシを返します。
典型的なUI Automatorテストは、物理デバイスを表すUiDeviceインスタンスを取得することから始まります。UiDeviceは、要素の検索、ボタン押下(ホーム、バック、最近)の管理、画面の回転、スクリーンショットの取得のためのメソッドを提供します。UiSelectorを介して要素を見つけた後、UiObjectに対してアクションが実行されます。
以下の例では、テストが設定アプリを開き、テキストで“バッテリー”項目を見つけてタップします。UI AutomatorはActivityの起動を必要としません — サードパーティアプリを含むデバイスの任意の画面で動作します。
val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
// 設定画面を開く
device.pressHome()
device.wait(Until.hasObject(UiSelector().text("設定")), 2000)
// "バッテリー"項目を探してタップ
val batteryItem = device.findObject(
UiSelector().text("バッテリー")
)
batteryItem.clickAndWait(Until.newWindow(), 3000)
UiDeviceはデバイスと対話するためのメインクラスです。要素の検索、ハードウェアボタン押下(ホーム、バック、メニュー、音量)のシミュレーション、電力管理、スクリーンショットの取得、特定の画面状態の待機のためのメソッドを提供します。UiDeviceはテストごとに1回作成され、すべての操作で再利用されます。
UiSelectorはUI要素を検索するためのfluent APIです。Espresso ViewMatchersとは異なり、UiSelectorはコンパイルを必要としません — 検索条件はメソッドチェーンを通じて形成されます:text()、className()、description()、resourceId()、index()。複数の条件は論理ANDを介して自動的に結合されます。
| UiSelectorメソッド | 目的 |
|---|---|
| text(String) | 要素の正確なテキストで検索 |
| textContains(String) | 部分的なテキスト一致で検索 |
| resourceId(String) | リソースIDで検索(例:com.example:id/button) |
| className(String) | Viewクラス名で検索 |
| description(String) | content-descriptionで検索 |
| childSelector(selector) | コンテナ内の子要素を検索 |
画面上に同じテキストを持つ複数の要素がある場合、UiSelectorは基準を組み合わせることができます:IDでコンテナを見つけ、その中で — テキストとクラスで要素を見つけます。これにより、目的のコンポーネントの一意の識別が保証されます。childSelectorメソッドは検索範囲を指定されたコンテナに絞り込み、UIツリーのナビゲーションを高速化します。
val scrollView = device.findObject(
UiSelector().resourceId("android:id/list")
)
// リスト内でテキスト"Wi-Fi"の要素を探す
val wifiItem = scrollView.findObject(
UiSelector().text("Wi-Fi")
wifiItem.click()
クロスアプリケーション(アプリ間)テストは、UI Automatorが選ばれる主な機能です。フレームワークはアプリ間を切り替え、ブラウザを介したOAuthログインをテストし、システムダイアログ(権限、アプリ選択)を確認し、システムステータスバー、通知パネル、ロック画面と対話できます。
典型的なクロスアプリテストシナリオ:アプリがOAuth認証のためにブラウザを開き、ユーザーがログインとパスワードを入力し、ブラウザがアプリにリダイレクトします。UI Automatorはプロセス間を切り替え、ブラウザの入力フィールドを見つけ、入力して“サインイン”をタップします。
// ブラウザの表示を待機
device.wait(Until.hasObject(
UiSelector().packageName("com.android.chrome")
), 5000)
// ブラウザでメール入力フィールドを検索
val emailField = device.findObject(
UiSelector().className("android.widget.EditText").instance(0)
)
emailField.text = "user@example.com"
UI Automatorはシステムダイアログを確認して閉じることができます — 位置情報の権限、通知、ファイルアクセス。これは、システムが複数の権限を順次要求する初回起動シナリオのテストにとって極めて重要です。UI Automatorがなければ、システムダイアログはアプリのプロセスに属さないため、これらのシナリオを自動化することはできません。
選択はテストシナリオによって異なります。Espressoは、自動同期と最小限のボイラープレートで単一アプリをテストするために最適化されています。UI Automatorは、システム、ブラウザ、または複数のアプリと対話する必要があるシナリオに適しています。
| 基準 | UI Automator | Espresso |
|---|---|---|
| 範囲 | デバイス全体、複数アプリ | 単一アプリ |
| 同期 | 手動(待機、スリープ) | 自動(Idling Resource) |
| 速度 | 低速(サービス経由のアクセス) | 高速(プロセス内で動作) |
| システムUI | 対応(通知、クイック設定) | 非対応 |
| 検索精度 | 属性によるUiSelector | タイプと階層によるViewMatchers |
| 安定性 | 低い(タイミングに依存) | 高い(自動待機) |
実際には、これらのフレームワークは一緒に使用されることがよくあります:Espressoは高い安定性でメインアプリのUIテストをカバーし、UI Automatorはアプリの境界を超えるシナリオ — OAuthログイン、システム権限、Share Intentの操作に使用されます。この組み合わせにより、最小限のテスト保守コストで最大のUIカバレッジが得られます。
統合は、build.gradleに依存関係を追加することで行われます。フレームワークはAndroidX Testの一部であり、マニフェストに追加の権限は必要ありません — インストゥルメンテッドテストが起動されると、Accessibility Serviceへのアクセスが自動的に設定されます。
最小構成には、uiautomatorアーティファクトと標準のAndroidJUnitRunnerテストランナーが含まれます。UI Automatorテストはsrc/androidTestディレクトリに配置され、Android API 18+を実行するエミュレータまたは物理デバイスで実行されます。
dependencies {
androidTestImplementation("androidx.test.uiautomator:uiautomator:2.3.0")
androidTestImplementation("androidx.test.ext:junit:1.2.1")
androidTestImplementation("androidx.test:runner:1.6.1")
}
UiDeviceインスタンスを取得するには、InstrumentationRegistry.getInstrumentation()を使用します。UiDeviceはsetUp()メソッドで一度作成し、デバイスリソースを節約するためにクラスのすべてのテストで再利用する必要があります。UiDeviceはスレッドセーフではないことに注意することが重要です — すべての操作はテストメソッドの同じスレッドで実行する必要があります。各テストで新しいUiDeviceを作成すると、オーバーヘッドが発生し、実行が遅くなります。beforeClassメソッドで一度UiDeviceを作成し、テストクラスのすべてのテストで再利用することをお勧めします。
Espressoとは異なり、UI Automatorには自動同期がありません。要素の表示を待機するには、UiDevice.wait(condition, timeout)メソッドをUntilオブジェクトとともに使用します:Until.findObject(selector)、Until.hasObject(selector)、Until.gone(selector)。適切な待機がないと、競合状態のためにテストが不安定になります — 検索時に要素が画面に表示されていない可能性があります。安定性のために、少なくとも3〜5秒のタイムアウトを設定することをお勧めします。
よくある質問
UI AutomatorはAccessibility Serviceレベルで動作し、任意のアプリと対話できます。Espressoは単一アプリのプロセス内で動作し、UIスレッドとの自動同期を使用します。UI Automatorはクロスアプリシナリオに優れ、Espressoは安定した単一アプリテストに優れています。
はい、UI AutomatorはAndroid API 18+を実行するすべてのデバイスで動作します。ルートアクセスは必要ありません — テスト起動時にInstrumentationを介してアクティブ化される標準のAccessibility Serviceを使用します。
UI AutomatorはAccessibility Serviceを使用して現在の画面の完全なUIコンポーネントツリーを取得します。次に、UiSelectorがこのツリーを走査し、指定された基準(テキスト、クラス、ID、content-description、またはそれらの組み合わせ)で要素を見つけます。
はい、UiDevice.takeScreenshot(storePath)メソッドを使用して現在の画面のスクリーンショットを撮り、ファイルに保存できます。これはデバッグに便利です:テストが失敗した場合、スクリーンショットを保存して画面の状態を分析できます。
UI Automatorには自動同期がないため、テストはタイミングに敏感です。アニメーションが完了していないか、Viewがまだレンダリングされていない場合、findObjectが要素を見つけられない可能性があります。解決策は、十分なタイムアウトを設定してUiDevice.wait()を使用することです。
まとめ
UI Automatorツールセットは、すべての主要なクロスアプリケーションテストシナリオをカバーし、システムレベルでのAndroid自動化の標準です。
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。