Spectatio は、実際のデバイスと仮想デバイスで Android Automotive OS (AAOS) をテストするために開発されたオープンソースのテスト フレームワークです。 Spectatio は、自動車デバイス上でアプリをテストするための API を提供し、AAOS とそのアプリの機能とパフォーマンスを検証するために使用される拡張可能でスケーラブルなソリューションです。
高度な設計
Spectatio フレームワークは、さまざまな AAOS UI 実装に適応および拡張可能です。これは、デバイス ハードウェア、エミュレーター、仮想化環境での AAOS の機能とパフォーマンスをテストするために使用されます。
次の図は、Spectatio フレームワークの高レベルの設計を説明しています。
図 1. Spectatio フレームワークの高レベル設計。
UI Automator上に構築された Spectatio フレームワークは、AAOS 上のユーザー アプリやシステム アプリと対話する UI テストを構築するための API セットを提供します。自動車テストでは、テスト用の Spectatio フレームワークによって提供される API を使用します。これにより、これらのテストがテスト対象デバイス (DUT) から独立し、サポートされている場合にはさまざまなデバイスをテストできるように拡張可能になります。
図 1 は、Spectatio フレームワークが、アプリ固有のインターフェイスとヘルパーを使用して、Dialer、Medicenter、Settings などの参照アプリに基づいてモジュール化されており、新しいアプリに簡単に拡張できることを示しています。 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 Tests は、アプリ ヘルパー実装関数を使用して、アプリに関連するさまざまな操作をテストします。 HelperAccessor
クラスを使用して、アプリ ヘルパー実装関数にアクセスします。
次のコードは、サンプルの自動車テストのセットアップ、クリーンアップ、および実行を示しています。
@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 つの要素に絞り込めるほど具体的に記述する必要があります。
文章
これは最も単純な UI 要素タイプです。 UI 要素はテキストによって識別され、完全に一致する必要があります。
"CALL_HISTORY_MENU": {
"TYPE": "TEXT",
"VALUE": "Recents"
}
TEXT_CONTAINS
TEXT
と同じですが、指定されたVALUE
、一致する要素のテキスト内のどこかに出現する必要があるだけです。
"PRIVACY_CALENDAR": {
"TYPE": "TEXT_CONTAINS",
"VALUE": "Calendar"
}
説明
要素はコンテンツ記述属性によって識別され、完全一致が必要です。
"APP_GRID_SCROLL_BACKWARD_BUTTON": {
"TYPE": "DESCRIPTION",
"VALUE": "Scroll up"
}
リソース_ID
リソース ID によって要素を識別し、必要に応じてその ID のパッケージ コンポーネントも確認します。 PACKAGE
キーはオプションです。省略した場合は、どのパッケージでも一致し、ID の:id/
に続く部分のみが考慮されます。
"APP_LIST_SCROLL_ELEMENT": {
"TYPE": "RESOURCE_ID",
"VALUE": "apps_grid",
"PACKAGE": "com.android.car.carlauncher"
}
クリック可能、スクロール可能
クリック可能またはスクロール可能かどうかに基づいて要素を識別します。これらは非常に幅広い要素タイプであり、通常は、別の要素タイプを絞り込むためにMULTIPLE
でのみ使用する必要があります。 FLAG
キーはオプションであり、デフォルトはtrue
です。
"SAMPLE_ELEMENT": {
"TYPE": "CLICKABLE",
"FLAG": false
}
クラス
クラスに基づいて要素を識別します。
"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"
}
}
複数
複数の同時条件に基づいて要素を識別します。これらの条件はすべて満たされる必要があります。
"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"
}
}
}
]
}
各ワークフローはキーと値のペアであり、キーはワークフローの名前、値は実行するアクションの配列です。各アクションには、 NAME
、 TYPE
、(通常は) CONFIG
、および(場合によっては) SWIPE_CONFIG
またはSCROLL_CONFIG
あります。ほとんどの TYPE では、 CONFIG
UI_ELEMENT
キーを持つオブジェクトであり、その値は UI 要素エントリと同じ形式になります (上記を参照)。それらのタイプは次のとおりです。
プレス 長押し クリック 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_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-NAMEAndroidAutomotiveSettingsTests
に設定します。 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 : テストクラスの名前。たとえば、 Wifi 設定テストの場合、テスト パッケージは
android.platform.tests
で、テスト クラス名はWifiSettingTest
です。
自動車スニペット ライブラリ
Automotive Snippet Library は、自動車のアプリやサービスと対話するように設計された Android オープンソース プロジェクト (AOSP) の Android テスト ライブラリのセットです。これは、ホスト (テスト) マシンから Android 搭載デバイスへのリモート プロシージャ コール (RPC) を実行するための便利なメカニズムで Spectatio を活用します。
始めましょう
始める前に、これらのセクションを確認してください。
前提条件
- Python 3.x がホスト マシンにインストールされている。
- 必要なビルド ツールを使用した AOSP 環境のセットアップ。
- adb アクセスを持つ Android 自動車デバイス (エミュレータまたは物理デバイス)。
編集
Automotive Snippet Library が提供するさまざまなスニペットをコンパイルするには、提供されているandroid.bp
ファイルを使用できます。前のセクションのコマンドに従って APK をコンパイルします。
導入
スニペット ライブラリのコンパイルが正常に完了したら、前のセクションで説明したadb install
コマンドを使用して、結果の APK をターゲット デバイスにデプロイします。
テストの実行
スニペット ライブラリは、自動車システムと対話するためのいくつかの RPC メソッドを公開します。これらのメソッドは、Mobly フレームワークを介してホスト マシンから呼び出すことができます。 Mobly テスト環境がセットアップされていると仮定すると、 snippet_shell.py
スクリプトを使用して対話型の Python シェルを開き、デバイス上で RPC メソッドを手動で呼び出すことができます。呼び出しの例:
python3 snippet_shell.py com.google.android.mobly.snippet.bundled -s <serial>
<serial>
デバイスのシリアル番号に置き換えます。これは、複数のデバイスが接続されている場合に adb devices で取得できます。
含まれるライブラリ
Automotive Snippet Library には、次のスニペット ライブラリとヘルパーが含まれています。
AutomotiveSnippet: ダイヤル、音量コントロール、車両ハード キー、メディア センター インタラクションなど、車両の操作に関連する API を提供します。
PhoneSnippet: 通話処理、連絡先の参照、SMS 操作などのテレフォニー関連の API を提供します。
Automotive スニペットと PhoneSnippet は、いくつかの共通ロジックを共有します。具体的には、Bluetooth 関連の RCP 呼び出しに侵入して、自動車と電話デバイスをペアリングすることができます。このbt_discovery_test
はその方法を示しています。
- TEST-CLASSNAME : テストクラスの名前。たとえば、 Wifi 設定テストの場合、テスト パッケージは
android.platform.tests
で、テスト クラス名はWifiSettingTest
です。