Spectatio — это тестовая платформа с открытым исходным кодом, разработанная для тестирования Android Automotive OS (AAOS) на реальных и виртуальных устройствах. Spectatio предоставляет API для тестирования приложений на автомобильных устройствах и представляет собой расширяемое и масштабируемое решение, используемое для проверки возможностей и производительности AAOS и её приложений.
Проектирование высокого уровня
Фреймворк Spectatio адаптируется и расширяется для различных реализаций пользовательского интерфейса AAOS. Он используется для тестирования возможностей и производительности AAOS на аппаратном обеспечении устройств, эмуляторах и виртуализированных средах.
The following figure explains the high-level design of the Spectatio framework.

Рисунок 1. Высокоуровневая схема проектирования структуры Spectatio.
Созданный на основе UI Automator , фреймворк Spectatio предоставляет набор API для создания тестов пользовательского интерфейса, взаимодействующих с пользовательскими и системными приложениями на AAOS. Автомобильные тесты используют API, предоставляемые фреймворком Spectatio, что делает эти тесты независимыми от тестируемого устройства (DUT) и масштабируемыми для тестирования различных устройств, если это поддерживается.
На рисунке 1 показано, что фреймворк Spectatio имеет модульную структуру, основанную на эталонных приложениях, таких как Dialer, Medicenter и Settings, с использованием интерфейсов и вспомогательных функций, специфичных для каждого приложения, что делает его легко расширяемым для новых приложений. Фреймворк Spectatio повторно использует общие стандартные и вспомогательные классы. Стандартный вспомогательный класс является родительским классом для всех вспомогательных функций приложения и предоставляет стандартные функции, специфичные для устройства или применимые ко всем приложениям. Вспомогательные классы предоставляют утилиты, такие как чтение или запись файлов с устройства.
Архитектура
Для предоставления набора API для создания UI-тестов фреймворк Spectatio реализует специфичные для приложения интерфейсы и вспомогательные функции, расширяя существующий стандартный класс вспомогательных функций и импортируя вспомогательные классы.
Figure 2 illustrates the high-level architecture of the Spectatio framework and all the entities involved in implementing APIs for testing an app.

Figure 2. Spectatio framework high-level architecture.
Интерфейс вспомогательного приложения предоставляет шаблон для реализации вспомогательного приложения. Он состоит из различных вспомогательных функций, необходимых для тестирования приложений. Каждое приложение имеет свой собственный интерфейс, например, IAutoSettingHelper и IAutoDialHelper . Для получения дополнительной информации и списка функций интерфейса см. раздел « Функции интерфейса вспомогательного приложения» на AOSP.
Стандартный вспомогательный класс состоит из стандартных атрибутов и функций, необходимых для настройки устройства, но не специфичных для какого-либо приложения, таких как pressHome и scroll . Стандартный вспомогательный класс определен в AbstractAutoStandardAppHelper.java .
Вспомогательные классы используются фреймворком. Например, AutoJsonUtility.java — это вспомогательный класс, который загружает заданный JSON-файл конфигурации устройства и обновляет конфигурации фреймворка во время выполнения.
Модуль реализации вспомогательных функций приложения является ядром фреймворка Spectatio. Он содержит реализацию вспомогательных функций, определенных в интерфейсе вспомогательных функций приложения, которые необходимы для тестирования приложений на автомобильных устройствах. Каждое приложение имеет свою собственную реализацию, например SettingHelperImpl и DialHelperImpl , используемые автомобильными тестами для проверки приложений. Для получения дополнительной информации и списка реализаций см. раздел «Функции реализации вспомогательных функций приложения » на AOSP.
В автомобильных тестах используются вспомогательные функции приложения для проверки различных операций, связанных с приложением. Используйте класс HelperAccessor для доступа к этим вспомогательным функциям.
The following code shows the setup, cleanup, and execution of a sample automotive test.
@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 , и должен содержать только информацию об изменениях пользовательского интерфейса для тестируемого устройства. Остальные элементы пользовательского интерфейса используют значения конфигурации по умолчанию, предоставленные фреймворком.
Настройки устройства по умолчанию
The following sample JSON configuration file shows the available device configurations and their default values.
Click here to display a sample JSON configuration file
{ "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" } } } }
Альтернативные конфигурации устройств
The following code sample shows an example of the JSON configuration file where default settings are overridden by the settings on the DUT. In this example:
Internet settings are named Network & internet on reference devices and Connectivity on the DUT.
The date and time settings are available at Settings > Date and time for reference devices and at Settings > System > Date and time for the 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"
},
....
}
When the JSON configuration file is ready, it's provided at runtime as shown in the following code block:
# Push The JSON configuration file to the device
adb -s DEVICE-SERIAL push PATH-OF-JSON-FILE /data/local/tmp/runtimeSpectatioConfig.json
В этой команде:
DEVICE-SERIAL : Serial ID of the DUT. This parameter isn`t required if only one device is connected to the host.
PATH-TO-JSON-FILE : Path of the JSON file on the host machine.
Формат конфигурации
There are five top-level objects in the configuration, with the following keys and values:
| Объект | Описание |
|---|---|
PACKAGES | An object describing the main package for various apps, which are used to determine when that app is in the foreground. |
ACTIONS | An object indicating action types and parameters for various actions. For example, whether to use buttons or a gesture to scroll. |
COMMANDS | An object specifying commands that perform various actions. |
UI_ELEMENTS | An object used to construct UI Automator `BySelectors` that select UI Elements (described in detail below). |
WORKFLOWS | Sequences of actions that accomplish high-level tasks (described in detail below). |
Элементы пользовательского интерфейса
Каждый элемент пользовательского интерфейса имеет TYPE , который определяет, что UI Automator будет искать для идентификации элемента (например, идентификатор ресурса, текст и описание), а также значения конфигурации, связанные с этим типом. Как правило, всякий раз, когда вспомогательный механизм идентифицирует элемент на экране, используя эту конфигурацию, он получает ровно один элемент. Если конфигурации соответствует несколько элементов, в тесте используется произвольный элемент. Поэтому конфигурация должна (как правило) быть написана достаточно конкретно, чтобы в соответствующем контексте она позволяла сузить круг поиска до одного элемента.
ТЕКСТ
This is the simplest UI element type. The UI element is identified by its text, and requires an exact match.
"CALL_HISTORY_MENU": {
"TYPE": "TEXT",
"VALUE": "Recents"
}
TEXT_CONTAINS
Same as TEXT , except that the specified VALUE only need appear somewhere in the text of the element to be matched.
"PRIVACY_CALENDAR": {
"TYPE": "TEXT_CONTAINS",
"VALUE": "Calendar"
}
ОПИСАНИЕ
Identify the element by its content description attribute, requiring an exact match.
"APP_GRID_SCROLL_BACKWARD_BUTTON": {
"TYPE": "DESCRIPTION",
"VALUE": "Scroll up"
}
RESOURCE_ID
Идентификатор элемента определяется по его идентификатору ресурса, при необходимости также проверяя компонент пакета этого идентификатора. Ключ PACKAGE является необязательным; если он опущен, будет найден любой пакет, и будет учитываться только та часть идентификатора, которая следует за :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"
}
}
НЕСКОЛЬКО
Identify the element based on multiple simultaneous conditions, all of which must be met.
"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"
}
}
]
}
In this example, the configuration identifies a RelativeLayout that has a descendant at depth 2 , which has the text 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 относятся:
| НАЖИМАТЬ ДЛИТЕЛЬНОЕ НАЖАТИЕ КЛИК ДЛИТЕЛЬНЫЙ КЛИК НАЖМИТЕ, ЕСЛИ СУЩЕСТВУЕТ | HAS_UI_ELEMENT_IN_FOREGROUND SCROLL_TO_FIND_AND_CLICK ПРОКРУТИТЕ ВНИЗ, ЧТОБЫ НАЙТИ И НАЖАТЬ, ЕСЛИ СУЩЕСТВУЕТ ПРОВЕДИТЕ МИНИМУМ, ЧТОБЫ НАЙТИ И НАЖАТЬ ПРОВЕДИТЕ МИНИМУМ, ЧТОБЫ НАЙТИ И НАЖАТЬ, ЕСЛИ СУЩЕСТВУЕТ |
For the other TYPEs, the configuration details are:
| Объект | Описание |
|---|---|
COMMAND | An object with a TEXT value containing the command to execute. |
HAS_PACKAGE_IN_FOREGROUND | An object with a TEXT value containing the package. |
SWIPE | Omit the CONFIG key for a SWIPE action. This uses only SWIPE_CONFIG |
WAIT_MS | An object with a TEXT value containing the number of milliseconds to wait. |
Scroll- and swipe-related actions require additional configuration, as follows:
SCROLL_CONFIG
| Объект | Описание |
|---|---|
SCROLL_ACTION | Либо USE_GESTURE , либо USE_BUTTON |
SCROLL_DIRECTION | Либо HORIZONTAL , либо VERTICAL |
SCROLL_ELEMENT | An object indicating the container to scroll, using the same form as a UI Element configuration (see above). |
SCROLL_FORWARD , SCROLL_BACKWARD | The forward and backward scroll buttons (required when SCROLL_ACTION is USE_BUTTON ). |
SCROLL_MARGIN | If SCROLL_ACTION is USE_GESTURE , the distance from the edge of the container to start and stop the drag that will be used to perform the scroll ( Optional, default = 10). |
SCROLL_WAIT_TIME | If SCROLL_ACTION is USE_GESTURE , the time in milliseconds to wait between scroll gestures when searching for an object to click. ( Optional, default = 1). |
SWIPE_CONFIG
| Объект | Описание |
|---|---|
SWIPE_DIRECTION | Either TOP_TO_BOTTOM , BOTTOM_TO_TOP , LEFT_TO_RIGHT , or RIGHT_TO_LEFT |
SWIPE_FRACTION | Один из следующих вариантов:
|
NUMBER_OF_STEPS | The number of steps to be used to perform the swipe. See segmentSteps . |
Создать и выполнить
Фреймворк Spectatio автоматически собирается как часть тестового APK-файла. Для сборки тестового APK-файла необходимо, чтобы код AOSP находился на локальной рабочей станции. После сборки тестового APK-файла пользователь должен установить APK-файл на устройство и запустить тест.
The following code sample shows the building, installation, and execution of a test 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, чтобы проверить настройки Wi-Fi, указанные в файлеAndroid.bp. Название APK-файла можно найти в соответствующем файлеAndroid.bpдля теста Automotive .DEVICE-SERIAL : The serial ID of the DUT. This parameter isn't required if only one device is connected to the host.
config-file-path: Необязательный параметр, необходимый только для предоставления нестандартных конфигураций пользовательского интерфейса устройства, указанных в файле конфигурации JSON . Если он не указан, фреймворк использует значения по умолчанию для выполнения тестов.PATH-FOR-BUILT-TEST-APK : The path where the test APK is built when the
makecommand is executed.TEST-PACKAGE : Название тестового пакета.
TEST-CLASSNAME : The name of the test class. For example, for the Wifi Settings test, the test package is
android.platform.testsand the test class name isWifiSettingTest.
Библиотека автомобильных фрагментов кода
Библиотека Automotive Snippet Library — это набор библиотек для тестирования Android-приложений в рамках проекта Android Open Source Project (AOSP), предназначенных для взаимодействия с автомобильными приложениями и сервисами. Она использует Spectatio с удобным механизмом для выполнения удаленных вызовов процедур (RPC) с хост-машины (тестовой) на устройство под управлением Android.
Начните
Прежде чем начать, ознакомьтесь с этими разделами.
Предварительные требования
- На хост-машине установлен Python 3.x.
- AOSP environment setup with necessary build tools.
- An Android automotive device (emulator or physical device) with adb access.
Компиляция
To compile the various snippets provided by the Automotive Snippet Library, you can use the provided android.bp file. Following commands in the previous section to compile the APK.
Развертывание
After successfully compiling the snippet libraries, deploy the resulting APKs to the target device using the adb install command mentioned in the previous section.
Запустите тесты
Библиотеки фрагментов кода предоставляют несколько методов RPC для взаимодействия с автомобильной системой. Эти методы можно вызывать через фреймворк Mobly с хост-машины. Предполагая, что у вас настроена тестовая среда Mobly, вы можете использовать скрипт snippet_shell.py для открытия интерактивной оболочки Python, где вы можете вручную вызывать методы RPC на устройстве. Пример вызова:
python3 snippet_shell.py com.google.android.mobly.snippet.bundled -s <serial>
Replace <serial> with the device serial number, which you can obtain with adb devices if multiple devices are connected.
Included libraries
The Automotive Snippet Library includes the following snippet libraries and helpers:
AutomotiveSnippet: Provides APIs related to vehicle operations, such as dialing, volume control, vehicle hard keys, and media center interaction.
PhoneSnippet: Provides telephony-related APIs, including call handling, contacts browsing, and SMS operations.
Фрагменты кода Automotive и PhoneSnippet имеют общую логику. В частности, вы можете перехватывать вызовы RCP, связанные с Bluetooth, для сопряжения автомобильного устройства и телефона. Этот bt_discovery_test демонстрирует, как это сделать.
- TEST-CLASSNAME : The name of the test class. For example, for the Wifi Settings test, the test package is
android.platform.testsand the test class name isWifiSettingTest.