Spectatio — это тестовая платформа с открытым исходным кодом, разработанная для тестирования Android Automotive OS (AAOS) на реальных и виртуальных устройствах. Spectatio предоставляет API для тестирования приложений на автомобильных устройствах и представляет собой расширяемое и масштабируемое решение для проверки возможностей и производительности AAOS и её приложений.
Высокоуровневый дизайн
Фреймворк Spectatio адаптируется и расширяется для различных реализаций пользовательского интерфейса AAOS. Он используется для тестирования возможностей и производительности AAOS на аппаратном обеспечении устройств, эмуляторах и виртуализированных средах.
На следующем рисунке показана общая схема структуры Spectatio.
Рисунок 1. Высокоуровневая конструкция фреймворка Spectatio.
Фреймворк Spectatio, построенный на основе UI Automator , предоставляет набор API для создания UI-тестов, взаимодействующих с пользовательскими и системными приложениями в AAOS. Автомобильные тесты используют API, предоставляемые фреймворком Spectatio для тестирования, что делает эти тесты независимыми от тестируемого устройства (DUT) и масштабируемыми для тестирования различных устройств, если поддерживается такая возможность.
На рисунке 1 показано, что фреймворк Spectatio модульный и основан на таких референтных приложениях, как Dialer, Medicenter и Settings, с использованием интерфейсов и вспомогательных функций, специфичных для приложений, что позволяет легко расширять его для новых приложений. Фреймворк Spectatio повторно использует общие стандартные и служебные вспомогательные классы. Стандартный вспомогательный класс является родительским классом для всех вспомогательных функций приложения и предоставляет стандартные функции, специфичные для устройства или применимые к другим приложениям. Вспомогательные классы предоставляют служебные функции, такие как чтение и запись файлов с устройства.
Архитектура
Чтобы предоставить набор API для создания тестов пользовательского интерфейса, фреймворк Spectatio реализует специфичные для приложения интерфейсы и вспомогательные методы, расширяя существующий стандартный вспомогательный класс и импортируя служебные вспомогательные классы.
На рисунке 2 показана высокоуровневая архитектура фреймворка Spectatio и всех объектов, участвующих в реализации API для тестирования приложения.
Рисунок 2. Высокоуровневая архитектура фреймворка Spectatio.
Интерфейс помощника приложения предоставляет план реализации помощника приложения. Он состоит из различных вспомогательных функций, необходимых для тестирования приложений. Каждое приложение имеет свой собственный интерфейс, например, IAutoSettingHelper
и IAutoDialHelper
. Дополнительную информацию и список функций интерфейса см. в разделе «Функции интерфейса помощника приложения» на сайте AOSP.
Стандартный вспомогательный класс состоит из стандартных атрибутов и функций, необходимых для настройки устройства, но не специфичных для какого-либо приложения, например, pressHome
и scroll
. Стандартный вспомогательный класс определен в AbstractAutoStandardAppHelper.java
.
Вспомогательные классы используются фреймворком. Например, AutoJsonUtility.java
— это вспомогательный класс, который загружает JSON-файл конфигурации заданного устройства и обновляет конфигурации фреймворка во время выполнения.
Модуль реализации вспомогательных функций приложений (app helper) является ядром фреймворка Spectatio. Он содержит реализацию вспомогательных функций, определённых в интерфейсе вспомогательных функций приложений (app helper), необходимых для тестирования приложений на автомобильном устройстве. Каждое приложение имеет собственную реализацию, например, 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
и должен содержать только информацию об изменениях пользовательского интерфейса для тестируемого устройства. Остальные элементы пользовательского интерфейса используют значения конфигурации по умолчанию, предоставленные фреймворком.
Конфигурации устройства по умолчанию
В следующем примере файла конфигурации 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, в котором настройки по умолчанию переопределяются настройками тестируемого устройства. В этом примере:
Настройки Интернета на эталонных устройствах называются «Сеть и Интернет» , а на проверяемом устройстве — «Подключение ».
Настройки даты и времени доступны в разделе Настройки > Дата и время для эталонных устройств и в разделе Настройки > Система > Дата и время для проверяемого устройства.
// 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 : Последовательный идентификатор тестируемого устройства. Этот параметр не требуется, если к хосту подключено только одно устройство.
PATH-TO-JSON-FILE : Путь к файлу JSON на хост-компьютере.
Формат конфигурации
В конфигурации имеется пять объектов верхнего уровня со следующими ключами и значениями:
Объект | Описание |
---|---|
PACKAGES | Объект, описывающий основной пакет для различных приложений, который используется для определения того, находится ли приложение на переднем плане. |
ACTIONS | Объект, указывающий типы действий и параметры для различных действий. Например, использовать ли кнопки или жест для прокрутки. |
COMMANDS | Объект, задающий команды, выполняющие различные действия. |
UI_ELEMENTS | Объект, используемый для построения UI Automator `BySelectors`, который выбирает элементы UI (подробно описано ниже). |
WORKFLOWS | Последовательности действий, реализующие задачи высокого уровня (подробно описанные ниже). |
Элементы пользовательского интерфейса
У каждого элемента пользовательского интерфейса есть TYPE
, который определяет, что UI Automator будет искать для идентификации элемента (например, идентификатор ресурса, текст и описание), а также значения конфигурации, связанные с этим типом. Как правило, всякий раз, когда помощник идентифицирует элемент на экране с помощью этой конфигурации, он получает ровно один элемент. Если конфигурации соответствуют несколько элементов, в тесте используется произвольный элемент. Поэтому конфигурация (как правило) должна быть написана достаточно конкретно, чтобы сузить поиск до одного элемента в соответствующем контексте.
ТЕКСТ
Это простейший тип элемента пользовательского интерфейса. Элемент пользовательского интерфейса идентифицируется по тексту и требует точного соответствия.
"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
Идентифицируйте элемент по его идентификатору ресурса, при необходимости также проверив пакетный компонент этого идентификатора. Ключ 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"
}
}
НЕСКОЛЬКО
Определите элемент на основе нескольких одновременных условий, все из которых должны быть соблюдены.
"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:
НАЖИМАТЬ ДЛИТЕЛЬНОЕ НАЖАТИЕ ЩЕЛЧОК ДЛИТЕЛЬНЫЙ_ЩЕЛЧОК CLICK_IF_EXIST | HAS_UI_ELEMENT_IN_FOREGROUND ПРОКРУТИТЕ, ЧТОБЫ НАЙТИ И ЩЕЛКНИТЕ ПРОКРУТИТЕ_ТО_НАЙТИ_И_ЩЕЛКНИТЕ_ЕСЛИ_СУЩЕСТВУЕТ SWIPE_TO_FIND_AND_CLICK SWIPE_TO_FIND_AND_CLICK_IF_EXIST |
Для других ТИПОВ подробности конфигурации следующие:
Объект | Описание |
---|---|
COMMAND | Объект со значением TEXT , содержащий команду для выполнения. |
HAS_PACKAGE_IN_FOREGROUND | Объект со значением TEXT , содержащий пакет. |
SWIPE | Не используйте CONFIG key для действия SWIPE . Используется только 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
, чтобы протестировать настройки Wi-Fi, указанные в файлеAndroid.bp
. Имя APK-файла можно найти в соответствующем файлеAndroid.bp
для теста Automotive .DEVICE-SERIAL : серийный идентификатор тестируемого устройства. Этот параметр не требуется, если к хосту подключено только одно устройство.
config-file-path
: необязательный параметр, необходимый только для предоставления нестандартных конфигураций пользовательского интерфейса устройства, указанных в файле конфигурации JSON . Если параметр не указан, фреймворк использует значения по умолчанию для выполнения тестов.PATH-FOR-BUILT-TEST-APK : Путь, по которому собирается тестовый APK при выполнении команды
make
.TEST-PACKAGE : Название тестового пакета.
TEST-CLASSNAME : Имя тестового класса. Например, для теста настроек Wi-Fi тестовый пакет —
android.platform.tests
, а имя тестового класса —WifiSettingTest
.
Библиотека автомобильных фрагментов
Библиотека Automotive Snippet — это набор тестовых библиотек Android для проекта Android Open Source Project (AOSP), разработанный для взаимодействия с автомобильными приложениями и сервисами. Она использует Spectatio с удобным механизмом для выполнения удалённых вызовов процедур (RPC) с хост-машины (тестовой) на устройство Android.
Начать
Прежде чем начать, просмотрите эти разделы.
Предпосылки
- На хост-компьютере установлен Python 3.x.
- Настройка среды AOSP с необходимыми инструментами сборки.
- Автомобильное устройство Android (эмулятор или физическое устройство) с доступом к adb.
Компиляция
Для компиляции различных фрагментов кода, предоставляемых библиотекой Automotive Snippet Library, вы можете использовать предоставленный файл android.bp
. Для компиляции APK-файла выполните команды из предыдущего раздела.
Развертывание
После успешной компиляции библиотек фрагментов разверните полученные APK-файлы на целевом устройстве с помощью команды adb install
упомянутой в предыдущем разделе.
Проведение тестов
Библиотеки фрагментов предоставляют несколько методов RPC для взаимодействия с автомобильной системой. Эти методы можно вызывать через фреймворк Mobly с хост-машины. Если у вас настроена тестовая среда Mobly, вы можете использовать скрипт snippet_shell.py
для открытия интерактивной оболочки Python, где можно вручную вызывать методы RPC на устройстве. Пример вызова:
python3 snippet_shell.py com.google.android.mobly.snippet.bundled -s <serial>
Замените <serial>
серийным номером устройства, который можно получить с помощью adb devices, если подключено несколько устройств.
Включенные библиотеки
Библиотека автомобильных сниппетов включает в себя следующие библиотеки сниппетов и вспомогательные функции:
AutomotiveSnippet: предоставляет API, связанные с операциями с транспортным средством, такими как набор номера, регулировка громкости, управление аппаратными клавишами транспортного средства и взаимодействие с медиацентром.
PhoneSnippet: предоставляет API, связанные с телефонией, включая обработку вызовов, просмотр контактов и операции с SMS.
Фрагменты Automotive и PhoneSnippet имеют общую логику. В частности, вы можете использовать RCP-вызовы, связанные с Bluetooth, для сопряжения автомобильного устройства и телефона. В этом bt_discovery_test
показано, как это сделать.
- TEST-CLASSNAME : Имя тестового класса. Например, для теста настроек Wi-Fi тестовый пакет —
android.platform.tests
, а имя тестового класса —WifiSettingTest
.