Spectatio: система автомобильных испытаний

Spectatio — это тестовая платформа с открытым исходным кодом, разработанная для тестирования Android Automotive OS (AAOS) на реальных и виртуальных устройствах. Spectatio предоставляет API для тестирования приложений на автомобильных устройствах и представляет собой расширяемое и масштабируемое решение для проверки возможностей и производительности AAOS и её приложений.

Высокоуровневый дизайн

Фреймворк Spectatio адаптируется и расширяется для различных реализаций пользовательского интерфейса AAOS. Он используется для тестирования возможностей и производительности AAOS на аппаратном обеспечении устройств, эмуляторах и виртуализированных средах.

На следующем рисунке показана общая схема структуры Spectatio.

Высокоуровневое проектирование фреймворка Spectatio

Рисунок 1. Высокоуровневая конструкция фреймворка Spectatio.

Фреймворк Spectatio, построенный на основе UI Automator , предоставляет набор API для создания UI-тестов, взаимодействующих с пользовательскими и системными приложениями в AAOS. Автомобильные тесты используют API, предоставляемые фреймворком Spectatio для тестирования, что делает эти тесты независимыми от тестируемого устройства (DUT) и масштабируемыми для тестирования различных устройств, если поддерживается такая возможность.

На рисунке 1 показано, что фреймворк Spectatio модульный и основан на таких референтных приложениях, как Dialer, Medicenter и Settings, с использованием интерфейсов и вспомогательных функций, специфичных для приложений, что позволяет легко расширять его для новых приложений. Фреймворк Spectatio повторно использует общие стандартные и служебные вспомогательные классы. Стандартный вспомогательный класс является родительским классом для всех вспомогательных функций приложения и предоставляет стандартные функции, специфичные для устройства или применимые к другим приложениям. Вспомогательные классы предоставляют служебные функции, такие как чтение и запись файлов с устройства.

Архитектура

Чтобы предоставить набор API для создания тестов пользовательского интерфейса, фреймворк Spectatio реализует специфичные для приложения интерфейсы и вспомогательные методы, расширяя существующий стандартный вспомогательный класс и импортируя служебные вспомогательные классы.

На рисунке 2 показана высокоуровневая архитектура фреймворка Spectatio и всех объектов, участвующих в реализации API для тестирования приложения.

Архитектура высокого уровня фреймворка Spectatio

Рисунок 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

Один из следующих вариантов:

  • FULL : Проведите пальцем от края экрана до края экрана

    ИЛИ,
  • DEFAULT : От края до края экрана, с пятипиксельным (5) буфером с каждой стороны.

    ИЛИ,
  • THREE_QUARTER , HALF или QUARTER : Жест смахивания заканчивается в пяти (5) пикселях от края экрана и начинается в точке таким образом, чтобы он охватывал указанное расстояние экрана.
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 показано, как это сделать.