Spectatio to platforma testowa typu open source opracowana do testowania systemu operacyjnego Android Automotive (AAOS) na urządzeniach rzeczywistych i wirtualnych. Spectatio udostępnia interfejsy API do testowania aplikacji na urządzeniu samochodowym. Jest to rozszerzalne i skalowalne rozwiązanie służące do weryfikowania możliwości i wydajności systemu AAOS oraz jego aplikacji.
Ogólny projekt
Platforma Spectatio jest elastyczna i można ją rozbudowywać na potrzeby różnych implementacji interfejsu AAOS. Służy do testowania możliwości i wydajności systemu AAOS na sprzęcie urządzenia, emulatorach i w środowiskach wirtualnych.
Na ilustracji poniżej przedstawiono ogólny projekt platformy Spectatio.
Rysunek 1. Ogólny projekt platformy Spectatio.
Platforma Spectatio, oparta na UI Automator, udostępnia zestaw interfejsów API do tworzenia testów interfejsu, które wchodzą w interakcję z aplikacjami użytkownika i systemowymi w systemie AAOS. Testy samochodowe korzystają z interfejsów API udostępnianych przez platformę Spectatio, dzięki czemu są niezależne od testowanego urządzenia i można je skalować, aby testować różne urządzenia, jeśli są obsługiwane.
Rysunek 1 pokazuje, że platforma Spectatio jest podzielona na moduły na podstawie aplikacji referencyjnych, takich jak Dialer, Medicenter i Ustawienia, przy użyciu interfejsów i metod pomocniczych specyficznych dla aplikacji, co ułatwia rozszerzanie jej o nowe aplikacje. Platforma Spectatio ponownie wykorzystuje typowe standardowe i pomocnicze klasy narzędziowe. Klasa pomocnicza standard 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. Pomocnicze klasy narzędziowe udostępniają narzędzia, takie jak odczytywanie i zapisywanie plików z urządzenia.
Architektura
Aby udostępnić zestaw interfejsów API do tworzenia testów interfejsu, platforma Spectatio implementuje interfejsy i metody pomocnicze specyficzne dla aplikacji, rozszerzając istniejącą standardową klasę pomocniczą i importując pomocnicze klasy narzędziowe.
Rysunek 2 przedstawia ogólną architekturę platformy Spectatio oraz wszystkie elementy biorące udział w implementowaniu interfejsów API do testowania aplikacji.
Rysunek 2. Ogólna architektura platformy Spectatio.
Interfejs pomocniczy aplikacji stanowi plan implementacji metody pomocniczej aplikacji. Składa się z różnych funkcji pomocniczych, które są potrzebne do testowania aplikacji. Każda aplikacja ma własny interfejs, np. IAutoSettingHelper
i IAutoDialHelper.
Więcej informacji i listę funkcji interfejsu znajdziesz w sekcji Funkcje interfejsu pomocniczego aplikacji w AOSP.
Standardowa klasa pomocnicza składa się ze standardowych atrybutów i funkcji, które są wymagane do konfiguracji urządzenia, ale nie są specyficzne dla żadnej aplikacji, np. pressHome i scroll. Standardowa klasa pomocnicza jest zdefiniowana w AbstractAutoStandardAppHelper.java.
Pomocnicze klasy narzędziowe są używane przez platformę. Na
przykład, AutoJsonUtility.java to
klasa narzędziowa, która wczytuje podany plik konfiguracji JSON urządzenia i aktualizuje
konfiguracje platformy w czasie działania.
Moduł implementacji metody pomocniczej aplikacji jest podstawą platformy Spectatio. Zawiera implementację funkcji pomocniczych zdefiniowanych w interfejsie pomocniczym aplikacji, które są wymagane do testowania aplikacji na urządzeniu samochodowym. Każda aplikacja ma własną implementację, np. SettingHelperImpl
i
DialHelperImpl,
która jest używana przez
testy samochodowe do testowania aplikacji. Więcej informacji i listę
implementacji znajdziesz w sekcji Funkcje implementacji metody pomocniczej aplikacji
'w AOSP.
Testy samochodowe
używają funkcji implementacji metody pomocniczej aplikacji do testowania różnych operacji
związanych z aplikacją. Aby uzyskać dostęp do funkcji implementacji metody pomocniczej aplikacji, użyj klasy HelperAccessor.
Poniższy kod pokazuje 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
Platforma Spectatio jest niezależna od interfejsu urządzenia, dzięki czemu można ją skalować do testowania urządzeń z różnymi interfejsami i sprzętem. Aby osiągnąć tę skalowalność, Spectatio używa domyślnych konfiguracji urządzeń opartych na urządzeniu referencyjnym. Aby obsługiwać konfiguracje urządzeń inne niż domyślne, platforma używa w czasie działania pliku konfiguracji JSON do ustawiania żądanych zmian interfejsu urządzenia. Plik konfiguracji JSON obsługuje elementy interfejsu, takie jak TEXT, DESCRIPTION i RESOURCE_ID, oraz ustawienia path. Musi zawierać tylko informacje o zmianach interfejsu testowanego urządzenia. Pozostałe elementy interfejsu używają domyślnych wartości konfiguracji podanych w platformie.
Domyślne konfiguracje urządzeń
W tym przykładowym pliku konfiguracji JSON znajdziesz dostępne konfiguracje urządzeń i ich wartości domyślne.
Kliknij tutaj, aby wyświetlić przykładowy plik konfiguracji 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 pokazuje przykład pliku konfiguracji JSON, w którym ustawienia domyślne są zastępowane ustawieniami na testowanym urządzeniu. W tym przykładzie:
Ustawienia internetowe mają nazwę Sieć i internet na urządzeniach referencyjnych oraz Łączność na testowanym urządzeniu.
Ustawienia daty i godziny są dostępne w sekcji Ustawienia > Data i godzina na urządzeniach referencyjnych oraz w sekcji Ustawienia > System > Data i godzina na testowanym urządzeniu.
// 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 konfiguracji JSON jest gotowy, jest udostępniany w czasie działania, jak pokazano w tym 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: numer seryjny testowanego urządzenia. Ten parametr nie jest wymagany, jeśli do hosta jest podłączone tylko 1 urządzenie.
PATH-TO-JSON-FILE: ścieżka do pliku JSON na komputerze hosta.
Format konfiguracji
W konfiguracji jest 5 obiektów najwyższego poziomu z tymi kluczami i wartościami:
| Obiekt | Opis |
|---|---|
PACKAGES |
Obiekt opisujący główny pakiet różnych aplikacji, który służy do określania, kiedy aplikacja jest na pierwszym planie. |
ACTIONS |
Obiekt wskazujący typy działań i parametry różnych działań. Na przykład czy do przewijania używać przycisków czy gestu. |
COMMANDS |
Obiekt określający polecenia, które wykonują różne działania. |
UI_ELEMENTS |
Obiekt używany do tworzenia `BySelectors` UI Automator, które wybierają elementy interfejsu (opisane szczegółowo poniżej). |
WORKFLOWS |
Sekwencje działań, które wykonują zadania na wysokim poziomie (opisane szczegółowo poniżej). |
Elementy interfejsu
Każdy element interfejsu ma TYPE, który określa, czego będzie szukać UI Automator, aby zidentyfikować element (np. identyfikator zasobu, tekst i opis), oraz wartości konfiguracji powiązane z tym typem. Ogólnie rzecz biorąc, gdy metoda pomocnicza zidentyfikuje element na ekranie za pomocą tej konfiguracji, otrzyma dokładnie 1 element. Jeśli do konfiguracji pasuje kilka elementów, w teście używany jest dowolny z nich. Dlatego konfiguracja powinna (zwykle) być wystarczająco szczegółowa, aby ograniczyć się do 1 elementu w odpowiednim kontekście.
TEXT
To najprostszy typ elementu interfejsu. Element interfejsu jest identyfikowany na podstawie tekstu i wymaga dokładnego dopasowania.
"CALL_HISTORY_MENU": {
"TYPE": "TEXT",
"VALUE": "Recents"
}
TEXT_CONTAINS
Tak samo jak TEXT, z tym wyjątkiem, że określona VALUE musi się pojawić tylko w tekście elementu, aby można było mówić o dopasowaniu.
"PRIVACY_CALENDAR": {
"TYPE": "TEXT_CONTAINS",
"VALUE": "Calendar"
}
DESCRIPTION
Identyfikuje element na podstawie atrybutu opisu treści, wymagając dokładnego dopasowania.
"APP_GRID_SCROLL_BACKWARD_BUTTON": {
"TYPE": "DESCRIPTION",
"VALUE": "Scroll up"
}
RESOURCE_ID
Identyfikuje element na podstawie jego identyfikatora zasobu, opcjonalnie sprawdzając też komponent pakietu tego identyfikatora. Klucz PACKAGE jest opcjonalny. Jeśli go pominiesz, będzie pasować dowolny pakiet, a pod uwagę będzie brana tylko część identyfikatora po :id/.
"APP_LIST_SCROLL_ELEMENT": {
"TYPE": "RESOURCE_ID",
"VALUE": "apps_grid",
"PACKAGE": "com.android.car.carlauncher"
}
CLICKABLE, SCROLLABLE
Identyfikuje element na podstawie tego, czy można go kliknąć lub przewinąć.
Są to bardzo ogólne typy elementów, które zwykle powinny być używane tylko w MULTIPLE, aby pomóc w zawężeniu innego typu elementu. Klucz FLAG jest opcjonalny i domyślnie ma wartość true.
"SAMPLE_ELEMENT": {
"TYPE": "CLICKABLE",
"FLAG": false
}
CLASS
Identyfikuje element na podstawie jego klasy.
"SECURITY_SETTINGS_ENTER_PASSWORD": {
"TYPE": "CLASS",
"VALUE": "android.widget.EditText"
}
HAS_ANCESTOR
Identyfikuje element, wyszukując w hierarchii widżetów jego elementy nadrzędne. Klucz ANCESTOR zawiera obiekt, który identyfikuje element nadrzędny. Klucz DEPTH określa, jak daleko w górę hierarchii należy szukać. DEPTH jest opcjonalny i domyślnie ma wartość 1.
"SAMPLE_ELEMENT": {
"TYPE": "HAS_ANCESTOR",
"DEPTH": 2,
"ANCESTOR": {
"TYPE": "CLASS",
"VALUE": "android.view.ViewGroup"
}
}
HAS_DESCENDANT
Identyfikuje element, wyszukując w hierarchii jego elementy podrzędne. Klucz DESCENDANT zawiera obiekt, który określa element podrzędny do wyszukania. Klucz DEPTH określa, jak daleko w górę hierarchii należy szukać. DEPTH jest opcjonalny i domyślnie ma wartość 1.
"SAMPLE_ELEMENT": {
"TYPE": "HAS_DESCENDANT",
"DEPTH": 2,
"DESCENDANT": {
"TYPE": "CLASS",
"VALUE": "android.view.ViewGroup"
}
}
MULTIPLE
Identyfikuje element na podstawie kilku warunków jednocześnie, 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 podrzędny na głębokości 2 z tekstem Permission manager.
Workflows
Workflow to sekwencja działań służących do wykonania określonego zadania, która może się różnić w zależności od typu urządzenia i jest bardziej elastyczna 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 workflow to para klucz-wartość, gdzie klucz to nazwa workflow, a wartość to tablica działań do wykonania. Każde działanie ma NAME, TYPE,
(zwykle) CONFIG i (czasami) SWIPE_CONFIG lub SCROLL_CONFIG. W przypadku większości typów CONFIG jest obiektem z kluczem UI_ELEMENT, którego wartość ma taką samą postać jak wpis elementu interfejsu (patrz wyżej). Te typy to:
| PRESS LONG_PRESS CLICK LONG_CLICK CLICK_IF_EXIST |
HAS_UI_ELEMENT_IN_FOREGROUND SCROLL_TO_FIND_AND_CLICK SCROLL_TO_FIND_AND_CLICK_IF_EXIST SWIPE_TO_FIND_AND_CLICK SWIPE_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 |
W przypadku działania SWIPE pomiń CONFIG key. Używa tylko SWIPE_CONFIG
. |
WAIT_MS |
Obiekt z wartością TEXT zawierającą liczbę
milisekund, przez które należy czekać. |
Działania związane z przewijaniem i przesuwaniem wymagają dodatkowej konfiguracji:
SCROLL_CONFIG
| Obiekt | Opis |
|---|---|
SCROLL_ACTION |
USE_GESTURE lub USE_BUTTON. |
SCROLL_DIRECTION |
HORIZONTAL lub VERTICAL. |
SCROLL_ELEMENT |
Obiekt wskazujący kontener do przewijania, używający tej samej postaci co konfiguracja elementu interfejsu (patrz wyżej). |
SCROLL_FORWARD, SCROLL_BACKWARD |
Przyciski przewijania do przodu i do tyłu (wymagane, gdy
SCROLL_ACTION ma wartość USE_BUTTON). |
SCROLL_MARGIN |
Jeśli SCROLL_ACTION ma wartość USE_GESTURE, odległość
od krawędzi kontenera, od której należy rozpocząć i zakończyć przeciąganie, które będzie używane
do przewijania (opcjonalne, domyślnie = 10). |
SCROLL_WAIT_TIME |
Jeśli SCROLL_ACTION ma wartość USE_GESTURE, czas w
milisekundach, przez który należy czekać między gestami przewijania podczas wyszukiwania obiektu do
kliknięcia.
(Opcjonalne,domyślnie = 1). |
SWIPE_CONFIG
| Obiekt | Opis |
|---|---|
SWIPE_DIRECTION |
TOP_TO_BOTTOM, BOTTOM_TO_TOP,
LEFT_TO_RIGHT lub RIGHT_TO_LEFT. |
SWIPE_FRACTION |
Jedna z tych wartości:
|
NUMBER_OF_STEPS |
Liczba kroków, które mają być użyte do wykonania przesunięcia palcem. Zobacz
segmentSteps.
|
Kompilacja i wykonanie
Platforma Spectatio jest automatycznie kompilowana w ramach testowego pliku APK. Aby skompilować testowy plik APK, baza kodu AOSP musi znajdować się na lokalnej stacji roboczej. Po skompilowaniu testowego pliku APK użytkownik musi zainstalować go na urządzeniu i wykonać test.
Poniższy przykładowy kod pokazuje kompilację, instalację i wykonanie testowego pliku 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 do przetestowania. Aby na przykład przetestować ustawienia Wi-Fi zgodnie z plikiem
Android.bp, ustaw TEST-APK-NAME naAndroidAutomotiveSettingsTests. Nazwę pliku APK można znaleźć w odpowiednim plikuAndroid.bpdla testu samochodowego.DEVICE-SERIAL: numer seryjny testowanego urządzenia. Ten parametr nie jest wymagany, jeśli do hosta jest podłączone tylko 1 urządzenie.
config-file-path: parametr opcjonalny, który jest wymagany tylko do podania niestandardowych konfiguracji interfejsu urządzenia zgodnie z plikiem konfiguracji JSON. Jeśli nie zostanie podany, platforma użyje wartości domyślnych do wykonania testów.PATH-FOR-BUILT-TEST-APK: ścieżka, w której jest kompilowany 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 kodu samochodowego
Biblioteka fragmentów kodu samochodowego to zestaw bibliotek testowych Androida dla projektu Android Open Source Project (AOSP), które służą do interakcji z aplikacjami i usługami samochodowymi. Wykorzystuje ona Spectatio z wygodnym mechanizmem wykonywania zdalnych wywołań procedur (RPC) z hosta (maszyny testowej) na urządzenie z Androidem.
Rozpocznij
Zanim zaczniesz, zapoznaj się z tymi sekcjami.
Wymagania wstępne
- Python 3.x zainstalowany na komputerze hosta.
- Środowisko AOSP skonfigurowane z niezbędnymi narzędziami do kompilacji.
- Urządzenie samochodowe z Androidem (emulator lub urządzenie fizyczne) z dostępem do adb.
Kompilacja
Aby skompilować różne fragmenty kodu udostępniane przez bibliotekę fragmentów kodu samochodowego, możesz
użyć podanego android.bp pliku. Aby skompilować plik APK, użyj poleceń z poprzedniej sekcji.
Wdrożenie
Po pomyślnej kompilacji bibliotek fragmentów kodu wdróż uzyskane pliki APK na urządzeniu docelowym za pomocą polecenia adb install wspomnianego w poprzedniej sekcji.
Przeprowadzanie testów
Biblioteki fragmentów kodu udostępniają kilka metod RPC do interakcji z systemem samochodowym. Metody te można wywoływać z komputera hosta za pomocą platformy Mobly. 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ład wywołania:
python3 snippet_shell.py com.google.android.mobly.snippet.bundled -s <serial>
Zastąp <serial> numerem seryjnym urządzenia, który możesz uzyskać za pomocą
adb devices, jeśli jest podłączonych kilka urządzeń.
Dołączone biblioteki
Biblioteka fragmentów kodu samochodowego zawiera te biblioteki fragmentów kodu i metody pomocnicze:
AutomotiveSnippet: udostępnia interfejsy API związane z obsługą pojazdu, takie jak wybieranie numeru, regulacja głośności, przyciski fizyczne pojazdu i interakcja z centrum multimediów.
PhoneSnippet: udostępnia interfejsy API związane z telefonią, w tym obsługę połączeń, przeglądanie kontaktów i operacje SMS.
Fragment kodu samochodowego i PhoneSnippet mają wspólną logikę.
Możesz na przykład użyć wywołań RCP związanych z Bluetooth, aby sparować urządzenie samochodowe i telefon. Pokazuje to bt_discovery_test.
- 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.