Spectatio 是一个开源测试框架,用于在真实设备和虚拟设备上测试 Android Automotive OS (AAOS)。Spectatio 提供 在汽车设备上测试应用,是一种可扩展、可伸缩的解决方案 用于验证 AAOS 及其应用的功能和性能。
概要设计
Spectatio 框架可适应各种 AAOS 界面实现,并相应地扩展。用于测试 AAOS 的功能和性能 在设备硬件、模拟器和虚拟环境中进行开发。
下图说明了 Spectatio 框架的概要设计。
图 1. Spectatio 框架概要设计。
Spectatio 框架基于 UI Automator 构建,提供了一组 API 构建与 AAOS 上的用户和系统应用交互的界面测试。汽车 这些测试使用 Spectatio 框架提供的 API 进行测试,这样, 这些测试独立于被测设备 (DUT),并且可扩展至测试 各种设备(如果支持的话)
图 1 显示 Spectatio 框架基于拨号器、Medicenter 和“设置”等参考应用实现了模块化,并使用应用专用的接口和辅助程序,使其能够针对新应用轻松扩展。Spectatio 框架会重复利用通用标准和实用程序辅助类。标准辅助类 是所有应用辅助函数的父类,提供 设备专用或适用于各种应用的标准功能。实用程序辅助类提供了各种实用程序,例如从设备读取或写入文件的实用程序。
架构
为了提供一组用于构建界面测试的 API,Spectatio 框架会实现 特定于应用的接口和帮助程序,同时扩展现有的标准帮助程序 类并导入实用程序辅助类。
图 2 展示了 Spectatio 框架的概要架构 实现用于测试应用的 API 所涉及的所有实体。
图 2. Spectatio 框架概要架构。
应用帮助程序接口提供了一个蓝图,用于实现
一个应用助手它包含测试应用所需的各种辅助函数。每个应用都有自己的接口,例如 IAutoSettingHelper
和 IAutoDialHelper
。如需了解详情并查看接口函数列表,请参阅 AOSP 上的应用辅助程序接口函数。
标准辅助类包含设备设置所需的标准属性和函数(但不特定于任何应用,例如 pressHome
和 scroll
)。标准辅助类需在 AbstractAutoStandardAppHelper.java
中定义。
Spectatio 框架会使用实用工具辅助类。对于
例如,AutoJsonUtility.java
是
实用程序类,用于加载给定的设备 JSON 配置文件和更新
框架配置。
应用帮助程序实现模块是 Spectatio 的核心
框架。它包含所定义的辅助函数的实现,
应用辅助接口,在
汽车设备。每个应用都有自己的实现,例如 SettingHelperImpl
和
DialHelperImpl
,
使用者
Automotive 测试,用于测试应用。如需了解更多信息和查看
请参阅应用帮助程序实现函数
。
汽车测试
使用应用辅助实现函数来测试各种操作
与应用相关使用 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 上的连接。
日期和时间设置可在设置 >日期和时间: 参考设备,并在设置 >系统 >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 Automator“BySelectors”的对象 元素(详见下文)。 |
WORKFLOWS |
用于完成高级任务的一系列操作(具体说明请参阅 )。 |
界面元素
每个界面元素都有一个 TYPE
,用于指定 UI Automator 查找的内容
标识相应元素(例如资源 ID、文本和说明)并
与该类型相关的配置值一般来说,只要
使用此配置标识屏幕上的元素时,它会准确获取
一个元素。如果有多个元素与配置匹配,可以选择任意元素
测试中使用的参数。因此,应(通常)编写配置
具体而言,它可以将范围缩小到相关上下文中的一个元素。
文字
这是最简单的界面元素类型。界面元素由其文本、 并且要求完全匹配。
"CALL_HISTORY_MENU": {
"TYPE": "TEXT",
"VALUE": "Recents"
}
文本内容
与 TEXT
相同,不同之处在于指定的 VALUE
只需要显示在以下位置的某个位置:
要匹配的元素的文本。
"PRIVACY_CALENDAR": {
"TYPE": "TEXT_CONTAINS",
"VALUE": "Calendar"
}
说明
通过内容说明属性标识元素,并要求其提供确切的 匹配。
"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"
}
可点击、可滚动
根据元素是否可点击或可滚动来识别元素。
这些是非常宽泛的元素类型,通常只应在
MULTIPLE
有助于缩小其他元素类型的范围。FLAG
键是可选的,
默认为 true
。
"SAMPLE_ELEMENT": {
"TYPE": "CLICKABLE",
"FLAG": false
}
类别
根据元素的类来标识元素。
"SECURITY_SETTINGS_ENTER_PASSWORD": {
"TYPE": "CLASS",
"VALUE": "android.widget.EditText"
}
HAS_ANCESTOR
通过在元素的祖先实体处查找 widget 层次结构来识别元素。通过
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"
}
}
]
}
在此示例中,配置标识了一个具有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 包括:
按下 LONG_PRESS 点击 LONG_CLICK CLICK_IF_EXIST |
HAS_UI_ELEMENT_IN_FOREGROUND SCROLL_TO_FIND_AND_CLICK SCROLL_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_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 设置。您可以在 Automotive 测试对应的Android.bp
文件中找到 APK 的名称。DEVICE-SERIAL:DUT 的序列号。此参数不是 如果只有一台设备连接到主机,则必须提供此值。
config-file-path
:可选参数,仅在提供 JSON 配置中指定的非默认设备用户界面配置 文件。如果未提供, 框架使用默认值来执行测试。PATH-FOR-BUILT-TEST-APK:系统在执行
make
命令时构建测试 APK 的路径。TEST-PACKAGE:测试软件包的名称。
TEST-CLASSNAME:测试类的名称。例如,对于 Wi-Fi 设置测试,测试软件包为
android.platform.tests
和 测试类名称为WifiSettingTest
。
汽车代码段库
Automotive 代码段库是一组 Android Test 库,适用于 旨在与汽车交互的 Android 开源项目 (AOSP) 应用及服务。它利用 Spectatio 提供了一种便捷的机制 用于执行从主机(测试)机器到 采用 Android 的手机。
开始使用
在开始之前,请先查看以下部分。
前提条件
- 在宿主机上安装 Python 3.x。
- 带有必要构建工具的 AOSP 环境设置。
- 具有 adb 访问权限的 Android Automotive 设备(模拟器或实体设备)。
编译
要编译 Automotive 代码段库提供的各种代码段,您需要
可以使用提供的 android.bp
文件。按照上一部分中的命令
部分来编译 APK。
部署
成功编译代码段库后,将生成的 APK 部署到
使用上述 adb install
命令访问目标设备
部分。
运行测试
代码段库公开了几种与汽车交互的 RPC 方法
系统。这些方法可以从主机通过 Mobly 框架调用
虚拟机。假设您已经设置了 Mobly 测试环境,则可以使用
snippet_shell.py
脚本来打开一个交互式 Python shell,在其中执行以下操作:
手动调用设备上的 RPC 方法。调用示例:
python3 snippet_shell.py com.google.android.mobly.snippet.bundled -s <serial>
将 <serial>
替换为设备序列号(您可以使用
adb 设备(如果连接了多台设备)。
包含的库
Automotive 代码段库包含以下代码段库和 帮助程序:
AutomotiveSnippet:提供与车辆操作相关的 API,例如 拨号、音量控制、车辆硬键以及媒体中心互动功能。
PhoneSnippet:提供与电话相关的 API,包括来电处理、 通讯录浏览和短信操作。
Automotive 代码段和 PhoneSnippet 具有一些共同的逻辑。
具体来说,您可以入侵与蓝牙相关的 RCP 调用,与汽车配对
和手机设备。此bt_discovery_test
展示了具体方法。
- TEST-CLASSNAME:测试类的名称。例如,对于 Wi-Fi 设置测试,测试软件包的名称为
android.platform.tests
,测试类的名称为WifiSettingTest
。