Spectatio to platforma testowa typu open source opracowana do testowania systemu operacyjnego Android Automotive OS (AAOS) na urządzeniach rzeczywistych i wirtualnych. Spectatio udostępnia interfejsy API do testowania aplikacji na urządzeniu samochodowym oraz jest rozszerzalnym i skalowalnym rozwiązaniem służącym do sprawdzania możliwości i wydajności AAOS i jego aplikacji.
Projekt na wysokim poziomie
Framework Spectatio można dostosowywać i rozszerzać pod kątem różnych implementacji interfejsu użytkownika AAOS. Służy do testowania możliwości i wydajności AAOS na sprzęcie urządzenia, emulatorach i środowiskach zwirtualizowanych.
Poniższy rysunek wyjaśnia ogólny projekt frameworku Spectatio.
Rysunek 1. Projekt wysokiego poziomu frameworku Spectatio.
Zbudowana na bazie UI Automator platforma Spectatio udostępnia zestaw interfejsów API do tworzenia testów interfejsu użytkownika, które wchodzą w interakcję z aplikacjami użytkownika i systemowymi w AAOS. Testy samochodowe wykorzystują do testowania interfejsy API dostarczane przez platformę Spectatio, co czyni te testy niezależnymi od testowanego urządzenia (DUT) i skalowalnymi w celu testowania różnych urządzeń, jeśli są obsługiwane.
Rysunek 1 pokazuje, że środowisko Spectatio jest zmodularyzowane w oparciu o aplikacje referencyjne, takie jak Dialer, Medicenter i Ustawienia, korzystające z interfejsów i pomocników specyficznych dla aplikacji, dzięki czemu można je łatwo rozszerzyć o nowe aplikacje. Framework Spectatio ponownie wykorzystuje wspólne klasy standardowe i pomocnicze. Standardowa klasa pomocnicza jest klasą nadrzędną dla wszystkich funkcji pomocniczych aplikacji i udostępnia standardowe funkcje, które są specyficzne dla urządzenia lub mają zastosowanie w różnych aplikacjach. Klasy pomocnicze narzędzi zapewniają narzędzia, takie jak odczytywanie i zapisywanie plików z urządzenia.
Architektura
Aby zapewnić zestaw interfejsów API do tworzenia testów interfejsu użytkownika, platforma Spectatio implementuje interfejsy i pomocniki specyficzne dla aplikacji, jednocześnie rozszerzając istniejącą standardową klasę pomocnika i importując klasy pomocników narzędzi.
Rysunek 2 ilustruje architekturę wysokiego poziomu frameworku Spectatio i wszystkie podmioty zaangażowane we wdrażanie interfejsów API do testowania aplikacji.
Rysunek 2. Architektura wysokiego poziomu platformy Spectatio.
Interfejs pomocnika aplikacji zapewnia plan implementacji pomocnika aplikacji. Składa się z różnych funkcji pomocniczych potrzebnych do testowania aplikacji. Każda aplikacja ma swój własny interfejs, taki jak IAutoSettingHelper
i IAutoDialHelper
. Aby uzyskać więcej informacji i listę funkcji interfejsu, zobacz funkcje interfejsu pomocniczego aplikacji w AOSP.
Standardowa klasa pomocnicza składa się ze standardowych atrybutów i funkcji wymaganych do konfiguracji urządzenia, ale nie jest specyficznych dla żadnej aplikacji, takich jak pressHome
i scroll
. Standardowa klasa pomocnicza jest zdefiniowana w AbstractAutoStandardAppHelper.java
.
Klasy pomocnicze narzędzi są używane przez platformę. Na przykład AutoJsonUtility.java
to klasa narzędziowa, która ładuje plik konfiguracyjny JSON danego urządzenia i aktualizuje konfiguracje struktury w czasie wykonywania.
Moduł implementacji pomocnika aplikacji stanowi rdzeń frameworka Spectatio. Zawiera implementację funkcji pomocniczych zdefiniowanych w interfejsie pomocniczym aplikacji, które są wymagane do testowania aplikacji na urządzeniu motoryzacyjnym. Każda aplikacja ma własną implementację, taką jak SettingHelperImpl
i DialHelperImpl
, używaną w testach motoryzacyjnych do testowania aplikacji. Aby uzyskać więcej informacji i listę implementacji, zobacz funkcje implementacji pomocnika aplikacji „w AOSP.
Testy samochodowe wykorzystują funkcje implementacji pomocnika aplikacji do testowania różnych operacji związanych z aplikacją. Użyj klasy HelperAccessor
, aby uzyskać dostęp do funkcji implementacji pomocnika aplikacji.
Poniższy kod przedstawia konfigurację, czyszczenie i wykonanie przykładowego testu samochodowego.
@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());
}
}
Dostosowywanie
Struktura Spectatio jest niezależna od interfejsu użytkownika urządzenia, dzięki czemu jest skalowalna w celu testowania urządzeń z różnymi interfejsami użytkownika i sprzętem. Aby osiągnąć tę skalowalność, Spectatio wykorzystuje domyślne konfiguracje urządzeń oparte na urządzeniu referencyjnym. Aby obsługiwać konfiguracje urządzeń inne niż domyślne, platforma używa pliku konfiguracyjnego JSON w czasie wykonywania, aby ustawić żądane zmiany interfejsu użytkownika dla urządzenia. Plik konfiguracyjny JSON obsługuje elementy interfejsu użytkownika, takie jak TEXT
, DESCRIPTION
i RESOURCE_ID
, wraz z ustawieniami path
i musi zawierać tylko informacje o zmianach interfejsu użytkownika dla testowanego urządzenia. Pozostałe elementy interfejsu użytkownika korzystają z domyślnych wartości konfiguracyjnych dostarczonych w ramach.
Domyślne konfiguracje urządzeń
Poniższy przykładowy plik konfiguracyjny JSON przedstawia dostępne konfiguracje urządzeń i ich wartości domyślne.
Kliknij tutaj, aby wyświetlić przykładowy plik konfiguracyjny 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" } } } }
Alternatywne konfiguracje urządzeń
Poniższy przykładowy kod przedstawia przykład pliku konfiguracyjnego JSON, w którym ustawienia domyślne są zastępowane przez ustawienia na urządzeniu DUT. W tym przykładzie:
Ustawienia internetowe noszą nazwy Sieć i Internet na urządzeniach referencyjnych oraz Łączność na urządzeniu DUT.
Ustawienia daty i godziny są dostępne w Ustawieniach > Data i godzina dla urządzeń referencyjnych oraz w Ustawienia > System > Data i godzina dla testowanego urządzenia.
// 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"
},
....
}
Gdy plik konfiguracyjny JSON jest gotowy, jest udostępniany w czasie wykonywania, jak pokazano w następującym bloku kodu:
# Push The JSON configuration file to the device
adb -s DEVICE-SERIAL push PATH-OF-JSON-FILE /data/local/tmp/runtimeSpectatioConfig.json
W tym poleceniu:
DEVICE-SERIAL : Identyfikator seryjny testowanego urządzenia. Parametr ten nie jest wymagany, jeśli do hosta podłączone jest tylko jedno urządzenie.
PATH-TO-JSON-FILE : Ścieżka pliku JSON na komputerze hosta.
Format konfiguracji
W konfiguracji znajduje się pięć obiektów najwyższego poziomu z następującymi kluczami i wartościami:
Obiekt | Opis |
---|---|
PACKAGES | Obiekt opisujący główny pakiet różnych aplikacji, który służy do określenia, kiedy dana aplikacja znajduje się na pierwszym planie. |
ACTIONS | Obiekt wskazujący typy akcji i parametry dla różnych akcji. Na przykład, czy do przewijania używać przycisków, czy gestów. |
COMMANDS | Obiekt określający polecenia wykonujące różne akcje. |
UI_ELEMENTS | Obiekt używany do konstruowania automatora interfejsu użytkownika „BySelectors”, który wybiera elementy interfejsu użytkownika (opisane szczegółowo poniżej). |
WORKFLOWS | Sekwencje działań realizujące zadania wysokiego poziomu (opisane szczegółowo poniżej). |
Elementy interfejsu użytkownika
Każdy element interfejsu użytkownika ma TYPE
, który określa, czego Automator interfejsu użytkownika będzie szukać, aby zidentyfikować element (np. identyfikator zasobu, tekst i opis) oraz wartości konfiguracyjne powiązane z tym typem. Ogólnie rzecz biorąc, ilekroć pomocnik zidentyfikuje element na ekranie przy użyciu tej konfiguracji, otrzymuje dokładnie jeden element. Jeżeli do konfiguracji pasuje wiele elementów, w teście używany jest dowolny. Dlatego konfiguracja powinna (zazwyczaj) być napisana na tyle szczegółowo, aby zawęzić ją do jednego elementu w odpowiednim kontekście.
TEKST
Jest to najprostszy typ elementu interfejsu użytkownika. Element interfejsu użytkownika jest identyfikowany przez tekst i wymaga dokładnego dopasowania.
"CALL_HISTORY_MENU": {
"TYPE": "TEXT",
"VALUE": "Recents"
}
TEXT_CONTAINS
To samo co TEXT
, z tą różnicą, że określona VALUE
musi jedynie pojawić się gdzieś w tekście elementu, który ma zostać dopasowany.
"PRIVACY_CALENDAR": {
"TYPE": "TEXT_CONTAINS",
"VALUE": "Calendar"
}
OPIS
Zidentyfikuj element na podstawie jego atrybutu opisu zawartości, co wymaga dokładnego dopasowania.
"APP_GRID_SCROLL_BACKWARD_BUTTON": {
"TYPE": "DESCRIPTION",
"VALUE": "Scroll up"
}
Identyfikator Zasobu
Zidentyfikuj element na podstawie jego identyfikatora zasobu, opcjonalnie sprawdzając także komponent pakietu o tym identyfikatorze. Klawisz PACKAGE
jest opcjonalny; jeśli zostanie pominięty, każdy pakiet będzie pasował i tylko część identyfikatora następująca po :id/
będzie brana pod uwagę.
"APP_LIST_SCROLL_ELEMENT": {
"TYPE": "RESOURCE_ID",
"VALUE": "apps_grid",
"PACKAGE": "com.android.car.carlauncher"
}
KLIKALNE, PRZEWIJANE
Zidentyfikuj element na podstawie tego, czy można go kliknąć lub przewijać (czy nie). Są to bardzo szerokie typy elementów i generalnie powinny być używane tylko w MULTIPLE
, aby pomóc zawęzić zakres innego typu elementu. Klawisz FLAG
jest opcjonalny i domyślnie ma wartość true
.
"SAMPLE_ELEMENT": {
"TYPE": "CLICKABLE",
"FLAG": false
}
KLASA
Zidentyfikuj element na podstawie jego klasy.
"SECURITY_SETTINGS_ENTER_PASSWORD": {
"TYPE": "CLASS",
"VALUE": "android.widget.EditText"
}
HAS_ANCESTOR
Zidentyfikuj element, przeglądając hierarchię widżetów pod kątem jego przodków. Klucz ANCESTOR
przechowuje obiekt identyfikujący przodka. Klawisz DEPTH
określa, jak wysoko w hierarchii należy szukać. DEPTH
jest opcjonalna i ma wartość domyślną 1
.
"SAMPLE_ELEMENT": {
"TYPE": "HAS_ANCESTOR",
"DEPTH": 2,
"ANCESTOR": {
"TYPE": "CLASS",
"VALUE": "android.view.ViewGroup"
}
}
HAS_DESCENDANT
Zidentyfikuj element, patrząc w dół hierarchii na jego dzieci. Klucz DESCENDANT
przechowuje obiekt określający dziecko, którego należy szukać. Klawisz DEPTH
określa, jak wysoko w hierarchii należy szukać. DEPTH
jest opcjonalna i ma wartość domyślną 1
.
"SAMPLE_ELEMENT": {
"TYPE": "HAS_DESCENDANT",
"DEPTH": 2,
"DESCENDANT": {
"TYPE": "CLASS",
"VALUE": "android.view.ViewGroup"
}
}
WIELE
Zidentyfikuj element na podstawie wielu jednoczesnych warunków, z których wszystkie muszą być spełnione.
"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"
}
}
]
}
W tym przykładzie konfiguracja identyfikuje RelativeLayout
, który ma element potomny na głębokości 2
i który zawiera tekst Permission manager
.
Przepływy pracy
Przepływ pracy reprezentuje sekwencję działań używanych do wykonania określonego zadania, która może różnić się w zależności od typu urządzenia i jest bardziej elastyczna do przedstawienia w konfiguracji niż w kodzie.
"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"
}
}
}
]
}
Każdy przepływ pracy to para klucz-wartość, gdzie klucz to nazwa przepływu pracy, a wartość to tablica działań do wykonania. Każda akcja ma NAME
, TYPE
, (zwykle) CONFIG
i (czasami) SWIPE_CONFIG
lub SCROLL_CONFIG
. Dla większości TYPÓW CONFIG
jest obiektem z kluczem UI_ELEMENT
, którego wartość przyjmuje taką samą formę jak wpis elementu UI (patrz wyżej). Te TYPY to:
NACISKAĆ LONG_PRESS KLIKNIJ LONG_CLICK KLIKNIJ_IF_ISTNIEJE | HAS_UI_ELEMENT_IN_FOREGROUND SCROLL_TO_FIND_AND_KLIKNIJ SCROLL_TO_FIND_AND_CLICK_IF_EXIST PRZESUŃ_TO_FIND_AND_KLIKNIJ PRZESUŃ_TO_FIND_AND_CLICK_IF_EXIST |
W przypadku pozostałych TYPÓW szczegóły konfiguracji są następujące:
Obiekt | Opis |
---|---|
COMMAND | Obiekt z wartością TEXT zawierającą polecenie do wykonania. |
HAS_PACKAGE_IN_FOREGROUND | Obiekt z wartością TEXT zawierającą pakiet. |
SWIPE | Pomiń CONFIG key dla akcji SWIPE . Używa tylko SWIPE_CONFIG |
WAIT_MS | Obiekt z wartością TEXT zawierającą liczbę milisekund oczekiwania. |
Działania związane z przewijaniem i przesuwaniem wymagają dodatkowej konfiguracji w następujący sposób:
SCROLL_CONFIG
Obiekt | Opis |
---|---|
SCROLL_ACTION | Albo USE_GESTURE , albo USE_BUTTON |
SCROLL_DIRECTION | HORIZONTAL lub VERTICAL |
SCROLL_ELEMENT | Obiekt wskazujący kontener do przewijania, przy użyciu tej samej formy co konfiguracja elementu interfejsu użytkownika (patrz wyżej). |
SCROLL_FORWARD , SCROLL_BACKWARD | Przyciski przewijania do przodu i do tyłu (wymagane, gdy SCROLL_ACTION ma USE_BUTTON ). |
SCROLL_MARGIN | Jeśli SCROLL_ACTION to USE_GESTURE , jest to odległość od krawędzi kontenera, na której rozpoczyna się i kończy przeciąganie, która będzie używana podczas przewijania ( opcjonalnie, domyślnie = 10). |
SCROLL_WAIT_TIME | Jeśli SCROLL_ACTION to USE_GESTURE , czas w milisekundach oczekiwania pomiędzy gestami przewijania podczas wyszukiwania obiektu do kliknięcia. ( Opcjonalnie, domyślnie = 1). |
PRZESUŃ_KONFIG
Obiekt | Opis |
---|---|
SWIPE_DIRECTION | Albo TOP_TO_BOTTOM , BOTTOM_TO_TOP , LEFT_TO_RIGHT , albo RIGHT_TO_LEFT |
SWIPE_FRACTION | Jeden z następujących:
|
NUMBER_OF_STEPS | Liczba kroków, które należy wykonać, aby wykonać przesunięcie. Zobacz segmentSteps . |
Buduj i wykonuj
Framework Spectatio jest tworzony automatycznie jako część testowego pliku APK. Aby zbudować testowy plik APK, baza kodu AOSP musi znajdować się na lokalnej stacji roboczej. Po zbudowaniu testowego pakietu APK użytkownik musi zainstalować plik APK na urządzeniu i przeprowadzić test.
Poniższy przykładowy kod przedstawia tworzenie, instalację i wykonanie testowego pakietu 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
W tych poleceniach:
TEST-APK-NAME : Nazwa aplikacji, która ma być testowana. Na przykład ustaw TEST-APK-NAME na
AndroidAutomotiveSettingsTests
, aby przetestować ustawienia Wi-Fi określone w plikuAndroid.bp
. Nazwę pakietu APK można znaleźć w odpowiednim plikuAndroid.bp
dla testu samochodowego .DEVICE-SERIAL : Identyfikator seryjny urządzenia DUT. Ten parametr nie jest wymagany, jeśli do hosta podłączone jest tylko jedno urządzenie.
config-file-path
: parametr opcjonalny, który jest wymagany tylko w celu zapewnienia konfiguracji interfejsu użytkownika urządzenia innych niż domyślne, jak określono w pliku konfiguracyjnym JSON . Jeśli nie zostanie podany, platforma używa wartości domyślnych do wykonywania testów.PATH-FOR-BUILT-TEST-APK : Ścieżka, w której tworzony jest testowy plik APK po wykonaniu polecenia
make
.TEST-PACKAGE : Nazwa pakietu testowego.
TEST-CLASSNAME : Nazwa klasy testowej. Na przykład w przypadku testu ustawień Wi-Fi pakiet testowy to
android.platform.tests
, a nazwa klasy testowej toWifiSettingTest
.
Biblioteka fragmentów motoryzacyjnych
Biblioteka fragmentów motoryzacyjnych to zestaw bibliotek testowych systemu Android dla projektu Android Open Source Project (AOSP), zaprojektowanych do interakcji z aplikacjami i usługami motoryzacyjnymi. Wykorzystuje Spectatio z wygodnym mechanizmem wykonywania zdalnych wywołań procedur (RPC) z komputera hosta (testowego) na urządzenie z systemem Android.
Zaczynaj
Zanim zaczniesz, przejrzyj te sekcje.
Warunki wstępne
- Python 3.x zainstalowany na komputerze hosta.
- Konfiguracja środowiska AOSP z niezbędnymi narzędziami do kompilacji.
- Urządzenie samochodowe z systemem Android (emulator lub urządzenie fizyczne) z dostępem adb.
Kompilacja
Aby skompilować różne fragmenty dostarczone przez Automotive Snippet Library, możesz użyć dostarczonego pliku android.bp
. Wykonaj polecenia z poprzedniej sekcji, aby skompilować plik APK.
Zastosowanie
Po pomyślnym skompilowaniu bibliotek fragmentów wdróż powstałe pliki APK na urządzeniu docelowym za pomocą polecenia adb install
wspomnianego w poprzedniej sekcji.
Uruchom testy
Biblioteki fragmentów udostępniają kilka metod RPC umożliwiających interakcję z systemem motoryzacyjnym. Metody te można wywołać za pośrednictwem platformy Mobly z komputera hosta. Zakładając, że masz skonfigurowane środowisko testowe Mobly, możesz użyć skryptu snippet_shell.py
, aby otworzyć interaktywną powłokę Pythona, w której możesz ręcznie wywoływać metody RPC na urządzeniu. Przykładowe wywołanie:
python3 snippet_shell.py com.google.android.mobly.snippet.bundled -s <serial>
Zastąp <serial>
numerem seryjnym urządzenia, który można uzyskać za pomocą urządzeń adb, jeśli podłączonych jest wiele urządzeń.
Dołączone biblioteki
Biblioteka fragmentów motoryzacyjnych zawiera następujące biblioteki fragmentów i pomocników:
AutomotiveSnippet: udostępnia interfejsy API związane z operacjami pojazdu, takimi jak wybieranie numerów, regulacja głośności, klawisze stałe pojazdu i interakcja z centrum multimedialnym.
PhoneSnippet: udostępnia interfejsy API związane z telefonią, w tym obsługę połączeń, przeglądanie kontaktów i operacje SMS.
Fragment Automotive i PhoneSnippet mają wspólną logikę. W szczególności możesz atakować połączenia RCP związane z Bluetooth, aby sparować samochód z urządzeniem telefonicznym. Ten bt_discovery_test
pokazuje, jak to zrobić.
- TEST-CLASSNAME : Nazwa klasy testowej. Na przykład w przypadku testu ustawień Wi-Fi pakiet testowy to
android.platform.tests
, a nazwa klasy testowej toWifiSettingTest
.