Spectatio 是一個開源測試框架,專為在真實和虛擬設備上測試 Android 汽車作業系統 (AAOS) 而開發。 Spectatio 提供用於測試汽車設備上的應用程式的 API,是一種可擴展且可擴展的解決方案,用於驗證 AAOS 及其應用程式的功能和性能。
高層設計
Spectatio 框架對於各種 AAOS UI 實作具有適應性和可擴展性。它用於測試 AAOS 在設備硬體、模擬器和虛擬化環境上的功能和效能。
下圖解釋了 Spectatio 框架的高層設計。
圖 1.Spectatio框架高層設計。
Spectatio 框架建構於UI Automator之上,提供了一組 API 來建立與 AAOS 上的使用者和系統應用程式互動的 UI 測試。汽車測試使用 Spectatio 框架提供的 API 進行測試,這使得這些測試獨立於被測設備 (DUT),並且可擴展以測試各種設備(如果支援)。
圖 1 顯示,Spectatio 框架是基於參考應用程式(例如 Dialer、Medicenter 和 Settings)使用特定於應用程式的介面和幫助程式進行模組化的,從而可以輕鬆擴展新應用程式。 Spectatio 框架重複使用了通用標準和實用幫助程式類別。標準幫助程式類別是所有應用程式幫助程式函數的父類,並提供特定於裝置或跨應用程式適用的標準函數。實用程式可協助程式類別提供實用程序,例如從裝置讀取或寫入檔案。
建築學
為了提供一組 API 來建立 UI 測試,Spectatio 框架實作了特定於應用程式的介面和幫助程序,同時擴展了現有的標準幫助程式類別並匯入了實用程式幫助程式類別。
圖 2 說明了 Spectatio 框架的高階架構以及參與實作用於測試應用程式的 API 的所有實體。
圖 2.Spectatio框架高層架構。
應用程式助手介面提供了應用程式助手的實作藍圖。它由測試應用程式所需的各種輔助函數組成。每個應用程式都有自己的介面,例如IAutoSettingHelper
和IAutoDialHelper
。如需更多資訊和介面函數列表,請參閱 AOSP 上的應用程式幫助器介面函數。
標準幫助程式類別由裝置設定所需的標準屬性和函數組成,但不特定於任何應用程序,例如pressHome
和scroll
。標準幫助器類別在AbstractAutoStandardAppHelper.java
中定義。
實用程式幫助器類別由框架使用。例如, AutoJsonUtility.java
是一個實用程式類,它會載入給定的裝置 JSON 設定檔並在執行時間更新框架設定。
應用程式助手實作模組是 Spectatio 框架的核心。它包含應用程式幫助程式介面中定義的幫助程式函數的實現,這是在汽車設備上測試應用程式所需的。每個應用程式都有自己的實現,例如SettingHelperImpl
和DialHelperImpl
,汽車測試使用它們來測試應用程式。有關更多資訊和實作列表,請參閱 AOSP 上的應用程式幫助器實作函數。
汽車測試使用應用程式幫助器實作函數來測試與應用程式相關的各種操作。使用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" } } } }
替代設備配置
以下程式碼範例顯示了 JSON 設定檔的範例,其中預設設定被 DUT 上的設定覆蓋。在這個例子中:
Internet 設定在參考裝置上命名為「網路與網際網路」 ,在 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 的序號。如果只有一台裝置連接到主機,則不需要此參數。
PATH-TO-JSON-FILE :主機上 JSON 檔案的路徑。
配置格式
配置中有五個頂級對象,具有以下鍵和值:
目的 | 描述 |
---|---|
PACKAGES | 描述各種應用程式主包的對象,用於確定該應用程式何時位於前台。 |
ACTIONS | 指示各種操作的操作類型和參數的物件。例如,是否使用按鈕或手勢滾動。 |
COMMANDS | 指定執行各種操作的命令的物件。 |
UI_ELEMENTS | 用於建構選擇 UI 元素的 UI Automator“BySelectors”的物件(下面詳細描述)。 |
WORKFLOWS | 完成高階任務的操作序列(詳細描述如下)。 |
使用者介面元素
每個 UI 元素都有一個TYPE
,它指定 UI Automator 將尋找什麼來識別元素(例如資源 ID、文字和描述)以及與該類型關聯的配置值。一般來說,每當助手使用此配置識別螢幕上的一個元素時,它就會準確地獲取一個元素。如果多個元素與配置匹配,則在測試中使用任意一個。因此,配置(通常)應該寫得足夠具體,以便將範圍縮小到相關上下文中的一個元素。
文字
這是最簡單的 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
鍵保存一個指定要尋找的子項的物件。 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
處具有後代的RelativeLayout
,該後代具有文字Permission manager
。
工作流程
工作流程表示用於完成特定任務的一系列操作,這些操作可能因設備類型而異,並且在配置中表示比在程式碼中表示更靈活。
"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
。對於大多數類型, CONFIG
是一個帶有UI_ELEMENT
鍵的對象,其值採用與 UI 元素條目相同的形式(見上文)。這些類型是:
按 長按 點選 長按 如果存在則點擊 | 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 |
對於其他 TYPE,配置詳細資訊為:
目的 | 描述 |
---|---|
COMMAND | 具有TEXT 值的對象,其中包含要執行的命令。 |
HAS_PACKAGE_IN_FOREGROUND | 具有包含包的TEXT 值的物件。 |
SWIPE | 省略SWIPE 操作的CONFIG key 。這僅使用SWIPE_CONFIG |
WAIT_MS | 具有TEXT 值的對象,其中包含要等待的毫秒數。 |
捲動和滑動相關的操作需要額外的配置,如下所示:
捲動配置
目的 | 描述 |
---|---|
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 :要測試的應用程式的名稱。例如,將TEST-APK-NAME設定為
AndroidAutomotiveSettingsTests
以測試Android.bp
檔案中指定的 Wi-Fi 設定。 APK 的名稱可以在汽車測試的對應Android.bp
檔案中找到。DEVICE-SERIAL :DUT 的序列 ID。如果只有一台裝置連接到主機,則不需要此參數。
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 測試庫,旨在與汽車應用和服務互動。它利用 Spectatio 的便利機制來執行從主機(測試)機器到 Android 裝置的遠端過程呼叫 (RPC)。
開始使用
在開始之前,請查看這些部分。
先決條件
- 主機上安裝了 Python 3.x。
- AOSP 環境設定以及必要的建置工具。
- 具有 adb 存取權限的 Android 汽車裝置(模擬器或實體裝置)。
彙編
要編譯汽車片段庫提供的各種片段,您可以使用提供的android.bp
檔。按照上一節的命令編譯 APK。
部署
成功編譯程式碼片段庫後,使用上一節中提到的adb install
指令將產生的 APK 部署到目標裝置。
運行測試
程式碼片段庫公開了多種 RPC 方法來與汽車系統互動。這些方法可以透過 Mobly 框架從主機呼叫。假設您已設定 Mobly 測試環境,則可以使用snippet_shell.py
腳本開啟互動式 Python shell,您可以在其中手動呼叫裝置上的 RPC 方法。呼叫範例:
python3 snippet_shell.py com.google.android.mobly.snippet.bundled -s <serial>
將<serial>
替換為設備序號,如果連接了多個設備,可以使用 adb devices 取得該序號。
包含的庫
汽車程式碼段庫包括以下程式碼段庫和幫助程式:
AutomotiveSnippet:提供與車輛操作相關的API,例如撥號、音量控制、車輛硬鍵、媒體中心互動等。
PhoneSnippet:提供與電話相關的 API,包括通話處理、聯絡人瀏覽和簡訊操作。
Automotive 程式碼片段和 PhoneSnippet 分享一些共同的邏輯。具體來說,您可以侵入與藍牙相關的 RCP 呼叫來配對汽車和電話設備。這個bt_discovery_test
顯示如何進行。
- TEST-CLASSNAME :測試類別的名稱。例如,對於Wifi 設定測試,測試包為
android.platform.tests
,測試類別名稱為WifiSettingTest
。