Spectatio 是一个开源测试框架,专为在真实和虚拟设备上测试 Android Automotive OS (AAOS) 而开发。Spectatio 提供用于测试汽车设备上应用的 API,并且是一个可扩展的解决方案,用于验证 AAOS 及其应用的功能和性能。
高级设计
Spectatio 框架具有适应性和可扩展性,适用于各种 AAOS 界面实现。它用于测试 AAOS 在设备硬件、模拟器和虚拟化环境中的功能和性能。
下图介绍了 Spectatio 框架的高级设计。
图 1. Spectatio 框架高级设计。
Spectatio 框架构建于 UI Automator 之上,提供了一组 API,用于构建与 AAOS 上的用户应用和系统应用互动的界面测试。汽车测试使用 Spectatio 框架提供的 API 进行测试,这使得这些测试独立于被测设备 (DUT),并且可扩展以测试各种受支持的设备。
图 1 显示,Spectatio 框架基于参考应用(例如“拨号器”、“媒体中心”和“设置”)使用特定于应用的接口和帮助程序进行模块化,从而使其易于扩展以支持新应用。Spectatio 框架重复使用通用的标准和实用工具帮助程序类。标准帮助程序类是所有应用帮助程序函数的父类,并提供特定于设备或适用于各种应用的标准函数。实用工具帮助程序类提供实用工具,例如从设备读取或写入文件。
架构
为了提供一组 API 来构建界面测试,Spectatio 框架实现了特定于应用的接口和帮助程序,同时扩展了现有的标准帮助程序类并导入了实用工具帮助程序类。
图 2 说明了 Spectatio 框架的高级架构以及实现用于测试应用的 API 所涉及的所有实体。
图 2. Spectatio 框架高级架构。
应用帮助程序接口为应用帮助程序的实现提供了蓝图。它包含测试应用所需的各种帮助程序函数。每个应用都有自己的接口,例如 IAutoSettingHelper
和 IAutoDialHelper
。如需了解详情以及接口函数列表,请参阅 AOSP 上的应用帮助程序接口函数。
标准帮助程序类包含设备设置所需的标准属性和函数,但不特定于任何应用,例如 pressHome
和 scroll
。标准帮助程序类在 AbstractAutoStandardAppHelper.java
中定义。
框架使用实用工具帮助程序类。例如,AutoJsonUtility.java
是一个实用工具类,用于加载给定的设备 JSON 配置文件并在运行时更新框架配置。
应用帮助程序实现模块是 Spectatio 框架的核心。它包含应用帮助程序接口中定义的帮助程序函数的实现,这些函数是测试汽车设备上的应用所必需的。每个应用都有自己的实现,例如 Automotive 测试用于测试应用的 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 框架独立于设备界面,因此可扩展用于测试具有各种界面和硬件的设备。为了实现这种可扩展性,Spectatio 使用基于参考设备的默认设备配置。为了支持非默认设备配置,该框架在运行时使用 JSON 配置文件来设置设备所需的界面更改。JSON 配置文件支持界面元素,例如 TEXT
、DESCRIPTION
和 RESOURCE_ID
,以及 path
设置,并且必须仅包含有关 DUT 的界面更改的信息。其余界面元素使用框架中提供的默认配置值。
默认设备配置
以下示例 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 上的设置覆盖。在此示例中
在参考设备上,互联网设置名为网络和互联网,而在 DUT 上名为 Connectivity。
日期和时间设置在参考设备上位于设置 > 日期和时间,而在 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。如果只有一个设备连接到主机,则此参数不是必需的。
PATH-TO-JSON-FILE:主机上的 JSON 文件路径。
配置格式
配置中有五个顶级对象,具有以下键和值
对象 | 说明 |
---|---|
PACKAGES |
一个对象,用于描述各种应用的主软件包,这些软件包用于确定该应用何时在前台。 |
ACTIONS |
一个对象,指示各种操作的操作类型和参数。例如,是使用按钮还是手势进行滚动。 |
COMMANDS |
一个对象,用于指定执行各种操作的命令。 |
UI_ELEMENTS |
一个对象,用于构造 UI Automator `BySelectors` 以选择界面元素(在下面详细介绍)。 |
WORKFLOWS |
用于完成高级任务的操作序列(在下面详细介绍)。 |
界面元素
每个界面元素都有一个 TYPE
,用于指定 UI Automator 将查找的内容以识别元素(例如资源 ID、文本和说明)以及与该类型关联的配置值。通常,每当帮助程序使用此配置在屏幕上识别元素时,它都会准确地获得一个元素。如果多个元素与配置匹配,则在测试中使用任意一个元素。因此,配置(通常)应编写得足够具体,以便将其缩小到相关上下文中的一个元素。
TEXT
这是最简单的界面元素类型。界面元素通过其文本进行标识,并且需要完全匹配。
"CALL_HISTORY_MENU": {
"TYPE": "TEXT",
"VALUE": "Recents"
}
TEXT_CONTAINS
与 TEXT
相同,不同之处在于,指定的 VALUE
只需要出现在要匹配的元素的文本中的某个位置。
"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"
}
}
]
}
在此示例中,配置标识一个 RelativeLayout
,该 RelativeLayout
在深度 2
处有一个后代,该后代的文本为 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
。对于大多数 TYPE,CONFIG
是一个对象,其中包含一个 UI_ELEMENT
键,其值与界面元素条目的形式相同(见上文)。这些 TYPE 是
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 |
对于其他 TYPE,配置详情如下
对象 | 说明 |
---|---|
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 |
一个对象,用于指示要滚动的容器,使用与界面元素配置相同的形式(见上文)。 |
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:要测试的应用的名称。例如,将 TEST-APK-NAME 设置为
AndroidAutomotiveSettingsTests
以测试Android.bp
文件中指定的 Wi-Fi 设置。APK 的名称可以在 汽车测试的相应Android.bp
文件中找到。DEVICE-SERIAL:DUT 的序列号 ID。如果只有一个设备连接到主机,则此参数不是必需的。
config-file-path
:可选参数,仅当需要提供非默认设备界面配置(如JSON 配置文件中所指定)时才需要。如果未提供,则框架将使用默认值来执行测试。PATH-FOR-BUILT-TEST-APK:执行
make
命令时构建测试 APK 的路径。TEST-PACKAGE:测试软件包的名称。
TEST-CLASSNAME:测试类的名称。例如,对于 Wifi 设置测试,测试软件包为
android.platform.tests
,测试类名称为WifiSettingTest
。
汽车代码段库
汽车代码段库是一组用于 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
。