Spectatio は、実際のデバイスと仮想デバイスで Android Automotive OS(AAOS)をテストするために開発されたオープンソースのテスト フレームワークです。Spectatio は、自動車デバイスでアプリをテストするための API を提供する拡張可能でスケーラブルなソリューションであり、AAOS および AAOS アプリの機能とパフォーマンスを検証するために使用できます。
設計の概要
Spectatio フレームワークは、さまざまな AAOS UI の実装に適用し、拡張することが可能です。デバイス ハードウェア、エミュレータ、仮想化された環境で AAOS の機能とパフォーマンスをテストするために使用されます。
次の図は、Spectatio フレームワークの設計の概要を示しています。
図 1. Spectatio フレームワークの設計の概要。
Spectatio フレームワークは UI Automator の上に構築されており、AAOS 上でユーザーアプリおよびシステムアプリとやり取りする UI テストを作成するための API のセットを提供します。Automotive テストでは、Spectatio フレームワークによってテスト用に提供される API が使用されます。それにより、テスト対象デバイス(DUT)からのテストの独立性と、サポートされているさまざまなデバイスでテストを行えるスケーラビリティが実現されます。
図 1 は、アプリ固有のインターフェースとヘルパーを使用して、電話アプリ、Medicenter、設定などのリファレンス アプリを基に Spectatio フレームワークをモジュール化し、新しいアプリ用に簡単に拡張できることを示しています。Spectatio フレームワークは、一般的な標準ヘルパークラスとユーティリティ ヘルパークラスを再利用します。標準ヘルパークラスは、すべてのアプリヘルパー関数の親クラスであり、デバイス固有の標準関数またはアプリ間で適用可能な標準関数を提供します。ユーティリティ ヘルパークラスは、デバイスからのファイルの読み取りや書き込みなどを行うユーティリティを提供します。
アーキテクチャ
UI テストを作成する API のセットを提供するため、Spectatio フレームワークはアプリ固有のインターフェースとヘルパーを実装します。また、その一方で既存の標準ヘルパークラスを拡張し、ユーティリティ ヘルパークラスをインポートします。
図 2 は、Spectatio フレームワークのアーキテクチャの概要と、アプリをテストするための API の実装に関係するすべてのエンティティを示しています。
図 2. Spectatio フレームワークのアーキテクチャの概要。
アプリヘルパー インターフェースは、アプリヘルパーの実装の青写真を提供します。これは、アプリのテストに必要なさまざまなヘルパー関数で構成されます。各アプリには、IAutoSettingHelper
や IAutoDialHelper
などの固有のインターフェースがあります。インターフェース関数の詳細とリストについては、AOSP のアプリヘルパー インターフェース関数をご覧ください。
標準ヘルパークラスは、pressHome
や scroll
のように、デバイスのセットアップに必要だがアプリに固有ではない標準の属性と関数で構成されます。標準ヘルパークラスは AbstractAutoStandardAppHelper.java
で定義されます。
ユーティリティ ヘルパークラスはフレームワークによって使用されます。たとえば、AutoJsonUtility.java
は、指定されたデバイスの JSON 構成ファイルを読み込み、実行時にフレームワーク構成を更新するユーティリティ クラスです。
アプリヘルパー実装モジュールは、Spectatio フレームワークの中核です。これは、自動車デバイスでアプリをテストするために必要な、アプリヘルパー インターフェース内で定義されたヘルパー関数の実装で構成されます。各アプリには、Automotive テストでアプリをテストするために使用される SettingHelperImpl
や DialHelperImpl
などの固有の実装があります。実装の詳細とリストについては、AOSP のアプリヘルパー実装関数をご覧ください。
Automotive テストでは、アプリに関係するさまざまなオペレーションをテストするために、アプリヘルパー実装関数を使用します。アプリヘルパー実装関数にアクセスするには、HelperAccessor
クラスを使用します。
次のコードは、サンプル Automotive テストのセットアップ、クリーンアップ、実行を示しています。
@RunWith(AndroidJUnit4.class)
public class AutoApplicationTest {
static HelperAccessor<IAutoApplicationHelper> autoApplicationHelper =
new HelperAccessor<>(IAutoApplicationHelper.class);
public AutoApplicationTest() {
// constructor
// Initialize any attributes that are required for the test execution
}
@Before
public void beforeTest() {
// Initial setup before each test
// For example - open the app
autoApplicationHelper.open();
}
@After
public void afterTest() {
// Cleanup after each test.
// For example - exit the app
autoApplicationHelper.exit();
}
@Test
public void testApplicationFeature() {
// Test
// For example - Test if app is open
assertTrue("Application is not open.", autoApplicationHelper.isOpen());
}
}
カスタマイズ
Spectatio フレームワークはデバイス UI から独立しているため、さまざまな UI とハードウェアでデバイスをテストできるスケーラビリティを備えています。このスケーラビリティを実現するため、Spectatio は参照デバイスに基づくデフォルトのデバイス設定を使用します。また、デフォルト以外のデバイス設定をサポートするため、フレームワークは実行時に JSON 構成ファイルを使用して、デバイスに必要な UI 変更を設定します。JSON 構成ファイルは、TEXT
、DESCRIPTION
、RESOURCE_ID
などの UI 要素を、path
設定とともにサポートします。このファイルは、DUT の UI 変更に関する情報のみを含む必要があります。残りの UI 要素については、フレームワークで提供されるデフォルトの構成値が使用されます。
デフォルトのデバイス設定
次の JSON 構成ファイルのサンプルは、使用可能なデバイス設定とそのデフォルト値を示しています。
こちらをクリックすると JSON 構成ファイルのサンプルが表示されます。
{ "SETTINGS": { "APPLICATION_CONFIG": { "SETTINGS_TITLE_TEXT": "Settings", "SETTINGS_PACKAGE": "com.android.car.settings", "SETTINGS_RRO_PACKAGE": "com.android.car.settings.googlecarui.rro", "OPEN_SETTINGS_COMMAND": "am start -a android.settings.SETTINGS", "OPEN_QUICK_SETTINGS_COMMAND": "am start -n com.android.car.settings/com.android.car.settings.common.CarSettingActivity" }, "QUICK_SETTINGS": { "OPEN_MORE_SETTINGS": { "TYPE": "RESOURCE_ID", "VALUE": "toolbar_menu_item_1", "PACKAGE": "com.android.car.settings" }, "NIGHT_MODE": { "TYPE": "TEXT", "VALUE": "Night mode" } }, "DISPLAY": { "PATH": "Settings > Display", "OPTIONS": [ "Brightness level" ], "BRIGHTNESS_LEVEL": { "TYPE": "RESOURCE_ID", "VALUE": "seekbar", "PACKAGE": "com.android.car.settings" } }, "SOUND": { "PATH": "Settings > Sound", "OPTIONS": [ "Media volume", "Alarm volume" ] }, "NETWORK_AND_INTERNET": { "PATH": "Settings > Network & internet", "OPTIONS": [ ], "TOGGLE_WIFI": { "TYPE": "RESOURCE_ID", "VALUE": "master_switch", "PACKAGE": "com.android.car.settings" } }, "BLUETOOTH": { "PATH": "Settings > Bluetooth", "OPTIONS": [ ], "TOGGLE_BLUETOOTH": { "TYPE": "RESOURCE_ID", "VALUE": "car_ui_toolbar_menu_item_switch", "PACKAGE": "com.android.car.settings" } }, "APPS_AND_NOTIFICATIONS": { "PATH": "Settings > Apps & notifications", "OPTIONS": [ ], "SHOW_ALL_APPS": { "TYPE": "TEXT", "VALUE": "Show all apps" }, "ENABLE_DISABLE_BUTTON": { "TYPE": "RESOURCE_ID", "VALUE": "car_ui_toolbar_menu_item_text", "PACKAGE": "com.android.car.settings" }, "DISABLE_BUTTON_TEXT": { "TYPE": "TEXT", "VALUE": "Disable" }, "ENABLE_BUTTON_TEXT": { "TYPE": "TEXT", "VALUE": "Enable" }, "DISABLE_APP_BUTTON": { "TYPE": "TEXT", "VALUE": "DISABLE APP" }, "FORCE_STOP_BUTTON": { "TYPE": "TEXT", "VALUE": "Force stop" }, "OK_BUTTON": { "TYPE": "TEXT", "VALUE": "OK" }, "PERMISSIONS_MENU": { "TYPE": "TEXT", "VALUE": "Permissions" }, "ALLOW_BUTTON": { "TYPE": "TEXT", "VALUE": "Allow" }, "DENY_BUTTON": { "TYPE": "TEXT", "VALUE": "Deny" }, "DENY_ANYWAY_BUTTON": { "TYPE": "TEXT", "VALUE": "Deny anyway" } }, "DATE_AND_TIME": { "PATH": "Settings > Date & time", "OPTIONS": [ "Automatic date & time", "Automatic time zone" ], "AUTOMATIC_DATE_AND_TIME": { "TYPE": "TEXT", "VALUE": "Automatic date & time" }, "AUTOMATIC_TIME_ZONE": { "TYPE": "TEXT", "VALUE": "Automatic time zone" }, "SET_DATE": { "TYPE": "TEXT", "VALUE": "Set date" }, "SET_TIME": { "TYPE": "TEXT", "VALUE": "Set time" }, "SELECT_TIME_ZONE": { "TYPE": "TEXT", "VALUE": "Select time zone" }, "USE_24_HOUR_FORMAT": { "TYPE": "TEXT", "VALUE": "Use 24-hour format" }, "OK_BUTTON": { "TYPE": "RESOURCE_ID", "VALUE": "toolbar_menu_item_0", "PACKAGE": "com.android.car.settings" }, "NUMBER_PICKER_WIDGET": { "TYPE": "CLASS", "VALUE": "android.widget.NumberPicker" }, "EDIT_TEXT_WIDGET": { "TYPE": "CLASS", "VALUE": "android.widget.EditText" } }, "USERS": { "PATH": "Settings > Users", "OPTIONS": [ "Guest" ] }, "ACCOUNTS": { "PATH": "Settings > Accounts", "OPTIONS": [ "Automatically sync data" ], "ADD_ACCOUNT": { "TYPE": "TEXT", "VALUE": "ADD ACCOUNT" }, "ADD_GOOGLE_ACCOUNT": { "TYPE": "TEXT", "VALUE": "Google" }, "SIGN_IN_ON_CAR_SCREEN": { "TYPE": "TEXT", "VALUE": "Sign in on car screen" }, "GOOGLE_SIGN_IN_SCREEN": { "TYPE": "TEXT", "VALUE": "Sign in to your Google Account" }, "ENTER_EMAIL": { "TYPE": "CLASS", "VALUE": "android.widget.EditText" }, "ENTER_PASSWORD": { "TYPE": "CLASS", "VALUE": "android.widget.EditText" }, "NEXT_BUTTON": { "TYPE": "TEXT", "VALUE": "Next" }, "DONE_BUTTON": { "TYPE": "TEXT", "VALUE": "Done" }, "REMOVE_BUTTON": { "TYPE": "TEXT", "VALUE": "Remove" }, "REMOVE_ACCOUNT_BUTTON": { "TYPE": "TEXT", "VALUE": "Remove Account" } }, "SYSTEM": { "PATH": "Settings > System", "OPTIONS": [ "About", "Legal information" ], "ABOUT_MENU": { "TYPE": "TEXT", "VALUE": "About" }, "RESET_OPTIONS_MENU": { "TYPE": "TEXT", "VALUE": "Reset options" }, "LANGUAGES_AND_INPUT_MENU": { "TYPE": "TEXT", "VALUE": "Languages & input" }, "DEVICE_MODEL": { "TYPE": "TEXT", "VALUE": "Model" }, "ANDROID_VERSION": { "TYPE": "TEXT", "VALUE": "Android version" }, "ANDROID_SECURITY_PATCH_LEVEL": { "TYPE": "TEXT", "VALUE": "Android security patch level" }, "KERNEL_VERSION": { "TYPE": "TEXT", "VALUE": "Kernel version" }, "BUILD_NUMBER": { "TYPE": "TEXT", "VALUE": "Build number" }, "RECYCLER_VIEW_WIDGET": { "TYPE": "CLASS", "VALUE": "androidx.recyclerview.widget.RecyclerView" }, "RESET_NETWORK": { "TYPE": "TEXT", "VALUE": "Reset network" }, "RESET_SETTINGS": { "TYPE": "TEXT", "VALUE": "RESET SETTINGS" }, "RESET_APP_PREFERENCES": { "TYPE": "TEXT", "VALUE": "Reset app preferences" }, "RESET_APPS": { "TYPE": "TEXT", "VALUE": "RESET APPS" }, "LANGUAGES_MENU": { "TYPE": "TEXT", "VALUE": "Languages" }, "LANGUAGES_MENU_IN_SELECTED_LANGUAGE": { "TYPE": "TEXT", "VALUE": "Idiomas" } }, "SECURITY": { "PATH": "Settings > Security", "OPTIONS": [ ], "TITLE": { "TYPE": "RESOURCE_ID", "VALUE": "car_ui_toolbar_title", "PACKAGE": "com.android.car.settings.googlecarui.rro" }, "CHOOSE_LOCK_TYPE": { "TYPE": "TEXT", "VALUE": "Choose a lock type" }, "LOCK_TYPE_PASSWORD": { "TYPE": "TEXT", "VALUE": "Password" }, "LOCK_TYPE_PIN": { "TYPE": "TEXT", "VALUE": "PIN" }, "LOCK_TYPE_NONE": { "TYPE": "TEXT", "VALUE": "None" }, "CONTINUE_BUTTON": { "TYPE": "TEXT", "VALUE": "Continue" }, "CONFIRM_BUTTON": { "TYPE": "TEXT", "VALUE": "Confirm" }, "ENTER_PASSWORD": { "TYPE": "CLASS", "VALUE": "android.widget.EditText" }, "PIN_PAD": { "TYPE": "RESOURCE_ID", "VALUE": "pin_pad", "PACKAGE": "com.android.car.settings" }, "ENTER_PIN_BUTTON": { "TYPE": "RESOURCE_ID", "VALUE": "key_enter", "PACKAGE": "com.android.car.settings" }, "REMOVE_BUTTON": { "TYPE": "TEXT", "VALUE": "Remove" } } }, "PHONE": { "APPLICATION_CONFIG": { "DIAL_PACKAGE": "com.android.car.dialer", "PHONE_ACTIVITY": "com.android.car.dialer/.ui.TelecomActivity", "OPEN_DIAL_PAD_COMMAND": "am start -a android.intent.action.DIAL" }, "IN_CALL_VIEW": { "DIALED_CONTACT_TITLE": { "TYPE": "RESOURCE_ID", "VALUE": "user_profile_title", "PACKAGE": "com.android.car.dialer" }, "DIALED_CONTACT_NUMBER": { "TYPE": "RESOURCE_ID", "VALUE": "user_profile_phone_number", "PACKAGE": "com.android.car.dialer" }, "END_CALL": { "TYPE": "RESOURCE_ID", "VALUE": "end_call_button", "PACKAGE": "com.android.car.dialer" }, "MUTE_CALL": { "TYPE": "RESOURCE_ID", "VALUE": "mute_button", "PACKAGE": "com.android.car.dialer" }, "SWITCH_TO_DIAL_PAD": { "TYPE": "RESOURCE_ID", "VALUE": "toggle_dialpad_button", "PACKAGE": "com.android.car.dialer" }, "CHANGE_VOICE_CHANNEL": { "TYPE": "RESOURCE_ID", "VALUE": "voice_channel_view", "PACKAGE": "com.android.car.dialer" }, "VOICE_CHANNEL_CAR": { "TYPE": "TEXT", "VALUE": "Car speakers" }, "VOICE_CHANNEL_PHONE": { "TYPE": "TEXT", "VALUE": "Phone" } }, "DIAL_PAD_VIEW": { "DIAL_PAD_MENU": { "TYPE": "TEXT", "VALUE": "Dial Pad" }, "DIAL_PAD_FRAGMENT": { "TYPE": "RESOURCE_ID", "VALUE": "dialpad_fragment", "PACKAGE": "com.android.car.dialer" }, "DIALED_NUMBER": { "TYPE": "RESOURCE_ID", "VALUE": "title", "PACKAGE": "com.android.car.dialer" }, "MAKE_CALL": { "TYPE": "RESOURCE_ID", "VALUE": "call_button", "PACKAGE": "com.android.car.dialer" }, "DELETE_NUMBER": { "TYPE": "RESOURCE_ID", "VALUE": "delete_button", "PACKAGE": "com.android.car.dialer" } }, "CONTACTS_VIEW": { "CONTACTS_MENU": { "TYPE": "TEXT", "VALUE": "Contacts" }, "CONTACT_INFO": { "TYPE": "RESOURCE_ID", "VALUE": "call_action_id", "PACKAGE": "com.android.car.dialer" }, "CONTACT_NAME": { "TYPE": "RESOURCE_ID", "VALUE": "title", "PACKAGE": "com.android.car.dialer" }, "CONTACT_DETAIL": { "TYPE": "RESOURCE_ID", "VALUE": "show_contact_detail_id", "PACKAGE": "com.android.car.dialer" }, "ADD_CONTACT_TO_FAVORITE": { "TYPE": "RESOURCE_ID", "VALUE": "contact_details_favorite_button", "PACKAGE": "com.android.car.dialer" }, "SEARCH_CONTACT": { "TYPE": "RESOURCE_ID", "VALUE": "menu_item_search", "PACKAGE": "com.android.car.dialer" }, "CONTACT_SEARCH_BAR": { "TYPE": "RESOURCE_ID", "VALUE": "car_ui_toolbar_search_bar", "PACKAGE": "com.android.car.dialer" }, "SEARCH_RESULT": { "TYPE": "RESOURCE_ID", "VALUE": "contact_name", "PACKAGE": "com.android.car.dialer" }, "CONTACT_SETTINGS": { "TYPE": "RESOURCE_ID", "VALUE": "menu_item_setting", "PACKAGE": "com.android.car.dialer" }, "CONTACT_ORDER": { "TYPE": "TEXT", "VALUE": "Contact order" }, "SORT_BY_FIRST_NAME": { "TYPE": "TEXT", "VALUE": "First name" }, "SORT_BY_LAST_NAME": { "TYPE": "TEXT", "VALUE": "Last Name" }, "CONTACT_TYPE_WORK": { "TYPE": "TEXT", "VALUE": "Work" }, "CONTACT_TYPE_MOBILE": { "TYPE": "TEXT", "VALUE": "Mobile" }, "CONTACT_TYPE_HOME": { "TYPE": "TEXT", "VALUE": "Home" } }, "CALL_HISTORY_VIEW": { "CALL_HISTORY_MENU": { "TYPE": "TEXT", "VALUE": "Recents" }, "CALL_HISTORY_INFO": { "TYPE": "RESOURCE_ID", "VALUE": "call_action_id", "PACKAGE": "com.android.car.dialer" } }, "FAVORITES_VIEW": { "FAVORITES_MENU": { "TYPE": "TEXT", "VALUE": "Favorites" } } }, "NOTIFICATIONS": { "APPLICATION_CONFIG": { "OPEN_NOTIFICATIONS_COMMAND": "service call statusbar 1" }, "EXPANDED_NOTIFICATIONS_SCREEN": { "NOTIFICATION_VIEW": { "TYPE": "RESOURCE_ID", "VALUE": "notification_view", "PACKAGE": "com.android.systemui" }, "CLEAR_ALL_BUTTON": { "TYPE": "RESOURCE_ID", "VALUE": "clear_all_button", "PACKAGE": "com.android.systemui" }, "STATUS_BAR": { "TYPE": "RESOURCE_ID", "VALUE": "car_top_navigation_bar_container", "PACKAGE": "com.android.systemui" }, "APP_ICON": { "TYPE": "RESOURCE_ID", "VALUE": "app_icon", "PACKAGE": "com.android.systemui" }, "APP_NAME": { "TYPE": "RESOURCE_ID", "VALUE": "header_text", "PACKAGE": "com.android.systemui" }, "NOTIFICATION_TITLE": { "TYPE": "RESOURCE_ID", "VALUE": "notification_body_title", "PACKAGE": "com.android.systemui" }, "NOTIFICATION_BODY": { "TYPE": "RESOURCE_ID", "VALUE": "notification_body_content", "PACKAGE": "com.android.systemui" }, "CARD_VIEW": { "TYPE": "RESOURCE_ID", "VALUE": "card_view", "PACKAGE": "com.android.systemui" } } }, "MEDIA_CENTER": { "APPLICATION_CONFIG": { "MEDIA_CENTER_PACKAGE": "com.android.car.media", "MEDIA_ACTIVITY": "com.android.bluetooth/com.android.bluetooth.avrcpcontroller.BluetoothMediaBrowserService" }, "MEDIA_CENTER_SCREEN": { "PLAY_PAUSE_BUTTON": { "TYPE": "RESOURCE_ID", "VALUE": "play_pause_stop", "PACKAGE": "com.android.car.media" }, "NEXT_BUTTON": { "TYPE": "RESOURCE_ID", "VALUE": "skip_next", "PACKAGE": "com.android.car.media" }, "PREVIOUS_BUTTON": { "TYPE": "RESOURCE_ID", "VALUE": "skip_prev", "PACKAGE": "com.android.car.media" }, "SHUFFLE_BUTTON": { "TYPE": "RESOURCE_ID", "VALUE": "overflow_on", "PACKAGE": "com.android.car.media" }, "PLAY_QUEUE_BUTTON": { "TYPE": "RESOURCE_ID", "VALUE": "play_queue", "PACKAGE": "com.android.car.media" }, "MINIMIZED_MEDIA_CONTROLS": { "TYPE": "RESOURCE_ID", "VALUE": "minimized_playback_controls", "PACKAGE": "com.android.car.media" }, "TRACK_NAME": { "TYPE": "RESOURCE_ID", "VALUE": "title", "PACKAGE": "com.android.car.media" }, "TRACK_NAME_MINIMIZED_CONTROL": { "TYPE": "RESOURCE_ID", "VALUE": "minimized_control_bar_title", "PACKAGE": "com.android.car.media" }, "BACK_BUTTON": { "TYPE": "DESCRIPTION", "VALUE": "Back" } }, "MEDIA_CENTER_ON_HOME_SCREEN": { "PLAY_PAUSE_BUTTON": { "TYPE": "RESOURCE_ID", "VALUE": "play_pause_stop", "PACKAGE": "com.android.car.carlauncher" }, "NEXT_BUTTON": { "TYPE": "RESOURCE_ID", "VALUE": "skip_next", "PACKAGE": "com.android.car.carlauncher" }, "PREVIOUS_BUTTON": { "TYPE": "RESOURCE_ID", "VALUE": "skip_prev", "PACKAGE": "com.android.car.carlauncher" }, "TRACK_NAME": { "TYPE": "RESOURCE_ID", "VALUE": "title", "PACKAGE": "com.android.car.carlauncher" } } } }
別のデバイス設定
次のコードサンプルは、デフォルト設定が DUT の設定によってオーバーライドされている JSON 構成ファイルの例です。次の例をご覧ください。
インターネット設定の名前は、参照デバイスの場合はネットワークとインターネット、DUT の場合は接続性です。
日付と時刻の設定は、参照デバイスの場合は [設定] > [日時]、DUT の場合は [設定] > [システム] > [日時] にあります。
// Default configuration file
{
....
"SECURITY_SETTINGS_SCROLL_ELEMENT": {
"TYPE": "RESOURCE_ID",
"VALUE": "fragment_container",
},
....
}
// JSON configuration file for non-reference device
{
....
"SECURITY_SETTINGS_SCROLL_ELEMENT": {
"TYPE": "RESOURCE_ID",
"VALUE": "car_ui_recycler_view"
},
....
}
JSON 構成ファイルの準備ができると、実行時に次のようなコードブロックで提供されます。
# Push The JSON configuration file to the device
adb -s DEVICE-SERIAL push PATH-OF-JSON-FILE /data/local/tmp/runtimeSpectatioConfig.json
コマンドの内容:
DEVICE-SERIAL: DUT のシリアル ID。ホストに接続されているデバイスが 1 台のみである場合、このパラメータは不要です。
PATH-TO-JSON-FILE: ホストマシン上の JSON ファイルのパス。
構成の形式
構成には、次のキーと値を含む 5 つの最上位のオブジェクトがあります。
オブジェクト | 説明 |
---|---|
PACKAGES |
さまざまなアプリのメイン パッケージを記述したオブジェクトで、そのアプリがいつフォアグラウンドにあるかを判断するために使用されます。 |
ACTIONS |
さまざまなアクションのアクション タイプとパラメータを示すオブジェクト。たとえば、スクロールするのにボタンを使用するかジェスチャーの操作を使用するかなどです。 |
COMMANDS |
さまざまなアクションを実行するコマンドを指定するオブジェクト。 |
UI_ELEMENTS |
UI 要素を選択する UI Automator「BySelectors」を構築するために使用されるオブジェクト(以下で詳しく説明)。 |
WORKFLOWS |
大まかなタスクを達成するための一連のアクション(以下で詳しく説明)。 |
UI 要素
各 UI 要素には TYPE
が含まれており、UI Automator が要素(リソース ID、テキスト、説明など)を識別するために何を検索するかと、そのタイプに関連付けられた構成値を指定します。一般的に、ヘルパーがこの構成を使用して画面上の要素を特定するたびに、要素を 1 つのみ取得します。複数の要素が構成と一致する場合、任意の要素がテストに使用されます。そのため、(一般的に)構成は、関連するコンテキスト内で 1 つの要素に絞り込まれるように具体的に記述する必要があります。
TEXT
これは最もシンプルな UI 要素タイプです。UI 要素はそのテキストで識別され、完全一致が要求されます。
"CALL_HISTORY_MENU": {
"TYPE": "TEXT",
"VALUE": "Recents"
}
TEXT_CONTAINS
指定された VALUE
が一致させる要素のテキストのどこかに表示されている必要があること以外は TEXT
と同じです。
"PRIVACY_CALENDAR": {
"TYPE": "TEXT_CONTAINS",
"VALUE": "Calendar"
}
DESCRIPTION
内容説明の属性で要素を識別し、完全一致を要求します。
"APP_GRID_SCROLL_BACKWARD_BUTTON": {
"TYPE": "DESCRIPTION",
"VALUE": "Scroll up"
}
RESOURCE_ID
リソース ID によって要素を識別し、必要に応じてその ID のパッケージ コンポーネントも確認します。PACKAGE
キーは省略可能です。省略した場合、どのパッケージでも突き合わせをして、:id/
に続く ID の部分のみが考慮されます。
"APP_LIST_SCROLL_ELEMENT": {
"TYPE": "RESOURCE_ID",
"VALUE": "apps_grid",
"PACKAGE": "com.android.car.carlauncher"
}
CLICKABLE、SCROLLABLE
クリック可能か(そうでないか)、スクロール可能かによって要素を識別します。これらは非常に広範な要素タイプです。一般的には別の要素タイプを絞り込むために MULTIPLE
でのみ使用してください。FLAG
キーは省略可能で、デフォルトは true
です。
"SAMPLE_ELEMENT": {
"TYPE": "CLICKABLE",
"FLAG": false
}
CLASS
クラスに基づいて要素を識別します。
"SECURITY_SETTINGS_ENTER_PASSWORD": {
"TYPE": "CLASS",
"VALUE": "android.widget.EditText"
}
HAS_ANCESTOR
ウィジェットの階層を祖先から調べて、要素を識別します。ANCESTOR
キーは、祖先を識別するオブジェクトを保持します。DEPTH
キーは、どの階層まで調べるかを指定します。DEPTH
は省略可能で、デフォルト値は 1
です。
"SAMPLE_ELEMENT": {
"TYPE": "HAS_ANCESTOR",
"DEPTH": 2,
"ANCESTOR": {
"TYPE": "CLASS",
"VALUE": "android.view.ViewGroup"
}
}
HAS_DESCENDANT
ウィジェットの階層を子から調べて、要素を識別します。DESCENDANT
キーは、子を識別するオブジェクトを保持します。DEPTH
キーは、どの階層まで調べるかを指定します。DEPTH
は省略可能で、デフォルト値は 1
です。
"SAMPLE_ELEMENT": {
"TYPE": "HAS_DESCENDANT",
"DEPTH": 2,
"DESCENDANT": {
"TYPE": "CLASS",
"VALUE": "android.view.ViewGroup"
}
}
MULTIPLE
複数の同時条件に基づいて要素を識別します。これらの同時条件はすべて満たされている必要があります。
"APP_INFO_SETTINGS_PERMISSION_MANAGER": {
"TYPE": "MULTIPLE",
"SPECIFIERS": [
{
"TYPE": "CLASS",
"VALUE": "android.widget.RelativeLayout"
},
{
"TYPE": "HAS_DESCENDANT",
"MAX_DEPTH": 2,
"DESCENDANT": {
"TYPE": "TEXT",
"VALUE": "Permission manager"
}
}
]
}
この例では、構成は深さ 2
の子孫があり、Permission manager
のテキストを含む RelativeLayout
を識別します。
ワークフロー
ワークフローは、特定のタスクを達成するために使用される一連のアクションを表します。デバイスの種類によって大きく異なる可能性があり、コードで表現するよりも構成で表現する方が柔軟性があります。
"WORKFLOWS": {
"OPEN_SOUND_SETTINGS_WORKFLOW": [
{
"NAME": "Go to Home",
"TYPE": "PRESS",
"CONFIG": {
"TEXT": "HOME"
}
},
{
"NAME": "Open Settings",
"TYPE": "COMMAND",
"CONFIG": {
"TEXT": "am start -a android.settings.SETTINGS"
}
},
{
"NAME": "Open Sound Settings",
"TYPE": "SCROLL_TO_FIND_AND_CLICK",
"CONFIG": {
"UI_ELEMENT": {
"TYPE": "TEXT",
"VALUE": "Sound"
}
},
"SCROLL_CONFIG": {
"SCROLL_ACTION": "USE_GESTURE",
"SCROLL_DIRECTION": "VERTICAL",
"SCROLL_ELEMENT": {
"TYPE": "RESOURCE_ID",
"VALUE": "car_ui_recycler_view"
}
}
}
]
}
各ワークフローは Key-Value ペアです。ここで、キーはワークフロー名、値は実行するアクションの配列です。各アクションには NAME
、TYPE
、(通常は)CONFIG
、(場合によっては)SWIPE_CONFIG
または SCROLL_CONFIG
が含まれます。ほとんどのタイプで、CONFIG
は UI_ELEMENT
キーを含むオブジェクトで、その値は UI 要素のエントリと同じ形式を使用します(上記を参照)。これらのタイプは次のとおりです。
PRESS LONG_PRESS CLICK LONG_CLICK CLICK_IF_EXIST |
HAS_UI_ELEMENT_IN_FOREGROUND SCROLL_TO_FIND_AND_CLICK SCROLL_TO_FIND_AND_CLICK_IF_EXIST SWIPE_TO_FIND_AND_CLICK SWIPE_TO_FIND_AND_CLICK_IF_EXIST |
そのほかのタイプの構成の詳細は次のとおりです。
オブジェクト | 説明 |
---|---|
COMMAND |
実行するコマンドを含む TEXT 値を使用したオブジェクト。 |
HAS_PACKAGE_IN_FOREGROUND |
パッケージを含む TEXT 値を使用したオブジェクト。 |
SWIPE |
SWIPE アクションでは CONFIG key を省略します。これは SWIPE_CONFIG のみを使用します。 |
WAIT_MS |
待機時間のミリ秒数を含む TEXT 値を使用したオブジェクト。 |
スクロールやスワイプに関連するアクションには、次のような追加の構成が必要です。
SCROLL_CONFIG
オブジェクト | 説明 |
---|---|
SCROLL_ACTION |
USE_GESTURE または USE_BUTTON |
SCROLL_DIRECTION |
HORIZONTAL または VERTICAL |
SCROLL_ELEMENT |
スクロールするコンテナを示すオブジェクト。UI 要素の構成と同じ形式を使用します(上記を参照)。 |
SCROLL_FORWARD 、SCROLL_BACKWARD |
前方と後方のスクロール ボタン(SCROLL_ACTION が USE_BUTTON のときに必要)。 |
SCROLL_MARGIN |
SCROLL_ACTION が USE_GESTURE の場合、コンテナの端から、スクロールを実行するためにドラッグを開始して停止するまでの距離(省略可。デフォルトは 10 です)。 |
SCROLL_WAIT_TIME |
SCROLL_ACTION が USE_GESTURE の場合、クリックするオブジェクトを検索するときに、スクロール操作を待つミリ秒数(省略可。デフォルトは 1 です)。 |
SWIPE_CONFIG
オブジェクト | 説明 |
---|---|
SWIPE_DIRECTION |
TOP_TO_BOTTOM 、BOTTOM_TO_TOP 、LEFT_TO_RIGHT または RIGHT_TO_LEFT |
SWIPE_FRACTION |
次のうちの一つ:
|
NUMBER_OF_STEPS |
スワイプを実行するのに使用されるステップ数。
segmentSteps をご覧ください。
|
ビルドと実行
Spectatio フレームワークは、テスト APK の一部として自動的にビルドされます。テスト APK をビルドするには、AOSP コードベースをローカル ワークステーションに配置する必要があります。テスト APK のビルドが完了した後、ユーザーはデバイスに APK をインストールしてテストを実行する必要があります。
次のコードサンプルは、テスト APK のビルド、インストール、実行を示しています。
# Build Test APK make TEST-APK-NAME
# Install Test APK adb -s DEVICE-SERIAL install -r PATH-FOR-BUILT-TEST-APK
# Execute Test with the JSON file adb -s DEVICE-SERIAL shell am instrument -w -r -e debug false -e config-file-path /data/local/tmp/jsonFile.json -e class TEST-PACKAGE.TEST-CLASSNAME TEST-PACKAGE/androidx.test.runner.AndroidJUnitRunner
上記のコマンドについて説明します。
TEST-APK-NAME: テスト対象アプリの名前。たとえば、
Android.bp
ファイルで指定された Wi-Fi 設定をテストするには、TEST-APK-NAME をAndroidAutomotiveSettingsTests
に設定します。APK の名前は、Automotive テストの各Android.bp
ファイルで確認できます。DEVICE-SERIAL: DUT のシリアル ID。ホストに接続されているデバイスが 1 台のみである場合、このパラメータは不要です。
config-file-path
: JSON 構成ファイルで指定された、デフォルト以外のデバイス UI 構成を提供する場合にのみ必要となる省略可能なパラメータ。このパラメータが指定されていない場合、フレームワークはデフォルト値を使用してテストを実行します。PATH-FOR-BUILT-TEST-APK:
make
コマンドが実行されたときにテスト APK がビルドされるパス。TEST-PACKAGE: テスト パッケージの名前。
TEST-CLASSNAME: テストクラスの名前。たとえば、Wi-Fi 設定テストの場合、テスト パッケージ名は
android.platform.tests
で、テストクラス名はWifiSettingTest
です。
Automotive スニペット ライブラリ
Automotive スニペット ライブラリは、Android オープンソース プロジェクト(AOSP)向けの Android テスト・ライブラリのセットで、Automotive アプリやサービスと連動するために設計されています。ホスト(テスト)マシンから Android 搭載デバイスにリモート プロシージャ コール(RPC)を実行するための便利なメカニズムで Spectatio を活用しています。
始める
開始する前にこれらのセクションを確認してください。
前提条件
- Python 3.x がホストマシンにインストールされている。
- 必要なビルドツールを備えた AOSP 環境のセットアップ。
- adb にアクセスできる Android Automotive デバイス(エミュレータまたは実機)。
コンパイル
Automotive スニペット ライブラリが提供するさまざまなスニペットをコンパイルするには、提供されている android.bp
ファイルを使用できます。前のセクションのコマンドを使用して APK をコンパイルします。
デプロイ
スニペット ライブラリをコンパイルしたら、前のセクションで説明した adb install
コマンドを使用して、生成される APK を対象デバイスにデプロイします。
テストを実行する
スニペット ライブラリは、Automotive システムと連動するためのいくつかの RPC メソッドを公開しています。これらのメソッドは、ホストマシンから Mobly フレームワークを介して起動できます。Mobly のテスト環境がセットアップされていることを前提として、snippet_shell.py
スクリプトを使用してインタラクティブな Python シェルを開き、そこでデバイス上の RPC メソッドを手動で起動できます。起動の例:
python3 snippet_shell.py com.google.android.mobly.snippet.bundled -s <serial>
<serial>
をデバイスのシリアル番号に置き換えます。複数のデバイスが接続されている場合は、adb デバイスを使って取得できます。
付属のライブラリ
Automotive スニペット ライブラリには、以下のスニペット ライブラリとヘルパーが含まれています。
AutomotiveSnippet: 発信、音量調節、車両ハードキー、メディア センターとのやり取りなど、車両操作に関連する API を提供します。
PhoneSnippet: 通話の処理、連絡先のブラウジング、SMS 操作など、電話関連の API を提供します。
AutomotiveSnippet と PhoneSnippet には共通のロジックがあります。具体的には、Bluetooth 関連の RCP 通話に入り込み、自動車とスマートフォンのデバイスをペア設定できます。こちらの bt_discovery_test
に方法が示されています。
- TEST-CLASSNAME: テストクラスの名前。たとえば、Wi-Fi 設定テストの場合、テスト パッケージ名は
android.platform.tests
で、テストクラス名はWifiSettingTest
です。