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
。