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 weryfikacji możliwości i wydajności AAOS oraz jego aplikacji.
Projektowanie na wysokim poziomie
Platforma Spectatio jest elastyczna i można ją rozszerzać, aby implementować różne interfejsy AAOS. Służy do testowania możliwości i wydajności AAOS na sprzęcie, emulatorach i w wirtualnych środowiskach.
Na rysunku poniżej przedstawiono ogólną strukturę 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 użytkownika, które współpracują z aplikacją użytkownika i aplikacją systemową na AAOS. Testy dotyczące pojazdów 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ć na różne urządzenia (jeśli są obsługiwane).
Jak widać na rysunku 1, platforma Spectatio jest podzielona na moduły na podstawie aplikacji referencyjnych, takich jak Dialer, Medicenter i Settings, z użyciem interfejsów i elementów pomocniczych dostępnych w przypadku poszczególnych aplikacji, co ułatwia rozszerzanie platformy o nowe aplikacje. Framework Spectatio używa ponownie standardowych klas pomocniczych i klas pomocniczych do obsługi. Standardowa klasa pomocnicza jest klasą nadrzędną dla wszystkich funkcji pomocniczych aplikacji i zawiera standardowe funkcje, które są specyficzne dla urządzenia lub mają zastosowanie w różnych aplikacjach. Klasy pomocnicze utility helper zapewniają takie funkcje, jak odczytywanie i zapisywanie plików z urządzenia.
Architektura
Aby zapewnić zestaw interfejsów API do tworzenia testów interfejsu użytkownika, framework Spectatio implementuje interfejsy i elementy pomocnicze związane z konkretną aplikacją, rozszerzając istniejące standardowe klasy pomocnicze oraz importując pomocnicze klasy pomocnicze.
Rysunek 2 przedstawia ogólną architekturę platformy Spectatio oraz wszystkie elementy zaangażowane w wdrażanie interfejsów API do testowania aplikacji.
Rysunek 2. Architektura ogólna platformy Spectatio
Interfejs aplikacji pomocniczej zawiera szablon implementacji aplikacji pomocniczej. Składa się on 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 funkcjach interfejsu pomocnika 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, takich jak pressHome
i scroll
. Standardowa klasa pomocnicza jest zdefiniowana w AbstractAutoStandardAppHelper.java
.
Framework korzysta z klas pomocniczych. Na przykład AutoJsonUtility.java
to klasa pomocnicza, która wczytuje plik konfiguracji JSON danego urządzenia i aktualizuje konfiguracje platformy w czasie wykonywania.
Moduł implementacji pomocy 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łasne wdrożenie, np. SettingHelperImpl
i DialHelperImpl
, które są używane przez testy Automotive do testowania aplikacji. Więcej informacji i listę implementacji znajdziesz w funkcjach implementacji pomocy aplikacji w AOSP.
Testy motoryzacyjne korzystają z funkcji implementacji aplikacji pomocniczej do testowania różnych operacji związanych z aplikacją. Aby uzyskać dostęp do funkcji implementacji aplikacji pomocniczej, użyj klasy HelperAccessor
.
Poniższy kod pokazuje konfigurację, sprzątanie 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 użytkownika urządzenia, dzięki czemu można ją skalować na potrzeby testowania urządzeń z różnymi interfejsami i sprzętem. Aby zapewnić taką skalowalność, Spectatio używa domyślnych konfiguracji urządzeń na podstawie urządzenia referencyjnego. Aby obsługiwać konfiguracje urządzeń inne niż domyślne, framework używa w czasie wykonywania pliku konfiguracyjnego JSON do wprowadzania na urządzeniu odpowiednich zmian w interfejsie użytkownika. Plik konfiguracji JSON obsługuje elementy interfejsu użytkownika, takie jak TEXT
, DESCRIPTION
i RESOURCE_ID
, a także ustawienia path
. Musi zawierać tylko informacje o zmianach interfejsu użytkownika w przypadku DUT. Pozostałe elementy interfejsu użytkownika korzystają z domyślnych wartości konfiguracji podanych w ramach.
Domyślne konfiguracje urządzenia
Poniższy przykładowy plik konfiguracji JSON zawiera dostępne konfiguracje urządzenia 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 plik konfiguracji JSON, w którym ustawienia domyślne są zastępowane przez ustawienia na urządzeniu testowym. W tym przykładzie:
Ustawienia internetu mają nazwę Sieć i internet na urządzeniach referencyjnych oraz Łączność na urządzeniu testowym.
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 urządzeniu testowanym.
// 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 on udostępniany w czasie wykonywania, 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 urządzenia DUT. Ten parametr nie jest wymagany, jeśli z hostem połączone jest tylko jedno 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 określający typy i parametry różnych działań. Na przykład czy do przewijania ma służyć przycisk czy gest. |
COMMANDS |
Obiekt określający polecenia wykonujące różne działania. |
UI_ELEMENTS |
Obiekt używany do tworzenia automatyzacji interfejsu użytkownika „BySelectors”, która wybiera elementy interfejsu (opisane szczegółowo poniżej). |
WORKFLOWS |
Sekwencje działań, które wykonują zadania ogólne (opisane szczegółowo poniżej). |
Elementy interfejsu
Każdy element interfejsu użytkownika ma atrybuty TYPE
, które określają, czego UI Automator będzie szukać, aby zidentyfikować element (np. identyfikator zasobu, tekst i opis), oraz wartości konfiguracji powiązane z tym typem. Ogólnie rzecz biorąc, gdy pomocnik rozpoznaje element na ekranie za pomocą tej konfiguracji, wybiera dokładnie jeden element. Jeśli konfiguracja pasuje do wielu elementów, w teście zostanie użyty dowolny z nich. Dlatego konfiguracja powinna być (ogółem) na tyle szczegółowa, aby zawężać ją do jednego elementu w odpowiednim kontekście.
TEKST
Jest to najprostszy typ elementu interfejsu. Element interfejsu użytkownika jest identyfikowany przez tekst i wymaga dopasowania ścisłego.
"CALL_HISTORY_MENU": {
"TYPE": "TEXT",
"VALUE": "Recents"
}
TEXT_CONTAINS
To samo co TEXT
, z tą różnicą, że określone VALUE
musi się tylko pojawić w tekście elementu, do którego ma być dopasowany.
"PRIVACY_CALENDAR": {
"TYPE": "TEXT_CONTAINS",
"VALUE": "Calendar"
}
OPIS
Identyfikuj element za pomocą atrybutu opisu treści, wymagając dokładnego dopasowania.
"APP_GRID_SCROLL_BACKWARD_BUTTON": {
"TYPE": "DESCRIPTION",
"VALUE": "Scroll up"
}
RESOURCE_ID
Identyfikuj element za pomocą jego identyfikatora zasobu, opcjonalnie sprawdzając również komponent pakietu tego identyfikatora. Klucz PACKAGE
jest opcjonalny. Jeśli go pominiesz, pasować będzie dowolny pakiet, a uwzględniona zostanie tylko część identyfikatora po :id/
.
"APP_LIST_SCROLL_ELEMENT": {
"TYPE": "RESOURCE_ID",
"VALUE": "apps_grid",
"PACKAGE": "com.android.car.carlauncher"
}
MOŻLIWOŚĆ KLIKANIA I PRZEWIJANIA
Określ, czy element można kliknąć lub przewinąć.
Są to bardzo ogólne typy elementów i zwykle należy ich używać tylko w elemencie MULTIPLE
, aby zawęzić zakres innego typu elementu. Klucz FLAG
jest opcjonalny i domyślnie ma wartość true
.
"SAMPLE_ELEMENT": {
"TYPE": "CLICKABLE",
"FLAG": false
}
CLASS
Określ element na podstawie jego klasy.
"SECURITY_SETTINGS_ENTER_PASSWORD": {
"TYPE": "CLASS",
"VALUE": "android.widget.EditText"
}
HAS_ANCESTOR
Identyfikuj element, wyszukując hierarchię widżetów w ich przodkach. Klucz ANCESTOR
zawiera obiekt, który identyfikuje przodka. Klucz DEPTH
określa, jak daleko w hierarchii mają być wyszukiwane dane. Opcjonalne pole DEPTH
ma domyślną wartość 1
.
"SAMPLE_ELEMENT": {
"TYPE": "HAS_ANCESTOR",
"DEPTH": 2,
"ANCESTOR": {
"TYPE": "CLASS",
"VALUE": "android.view.ViewGroup"
}
}
HAS_DESCENDANT
Identyfikuj element, przeglądając hierarchię w dół, czyli elementy podrzędne. Klucz DESCENDANT
zawiera obiekt, który określa element podrzędny do wyszukania. Klucz DEPTH
określa, jak daleko w hierarchii należy szukać. Parametr DEPTH
jest opcjonalny i ma domyślną wartość 1
.
"SAMPLE_ELEMENT": {
"TYPE": "HAS_DESCENDANT",
"DEPTH": 2,
"DESCENDANT": {
"TYPE": "CLASS",
"VALUE": "android.view.ViewGroup"
}
}
WIELE
Określ element na podstawie wielu warunków, które 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 wskazuje element RelativeLayout
, który ma potomka na poziomie 2
, i zawiera tekst Permission manager
.
Workflows
Proces to sekwencja działań służących do wykonania określonego zadania, która może się znacznie różnić w zależności od typu urządzenia. Procesy są bardziej elastyczne w użyciu 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 kluczem jest nazwa przepływu pracy, a wartością – tablica działań do wykonania. Każda czynność ma NAME
, TYPE
, (zwykle) CONFIG
i (czasami) SWIPE_CONFIG
lub SCROLL_CONFIG
. W przypadku większości typów CONFIG
to obiekt z kluczem UI_ELEMENT
, którego wartość ma tę samą postać co wpis elementu interfejsu użytkownika (patrz wyżej). Typy:
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 innych typów szczegóły konfiguracji to:
Obiekt | Opis |
---|---|
COMMAND |
Obiekt o wartości TEXT zawierający polecenie do wykonania. |
HAS_PACKAGE_IN_FOREGROUND |
Obiekt z wartością TEXT zawierający pakiet. |
SWIPE |
Pomiń CONFIG key w przypadku działania SWIPE . Ten eksperyment używa tylko SWIPE_CONFIG |
WAIT_MS |
Obiekt z wartością TEXT zawierającą liczbę milisekund oczekiwania. |
Czynności związane z przewijaniem i przesuwaniem wymagają dodatkowej konfiguracji:
SCROLL_CONFIG
Obiekt | Opis |
---|---|
SCROLL_ACTION |
Może to być USE_GESTURE lub USE_BUTTON . |
SCROLL_DIRECTION |
Może to być HORIZONTAL lub VERTICAL . |
SCROLL_ELEMENT |
Obiekt wskazujący kontener, który ma być przewijany, przy użyciu tego samego formularza co konfiguracja elementu interfejsu (patrz powyżej). |
SCROLL_FORWARD , SCROLL_BACKWARD |
przyciski przewijania do przodu i do tyłu (wymagane, gdy SCROLL_ACTION = USE_BUTTON ); |
SCROLL_MARGIN |
Jeśli SCROLL_ACTION to USE_GESTURE , odległość od krawędzi kontenera do punktu początkowego i końcowego przeciągania, który będzie używany do przewijania (opcjonalnie, domyślnie = 10). |
SCROLL_WAIT_TIME |
Jeśli SCROLL_ACTION to USE_GESTURE , czas w milisekundach, przez jaki należy czekać między gestami przewijania podczas wyszukiwania obiektu do kliknięcia.
(opcjonalne, domyślnie = 1). |
SWIPE_CONFIG
Obiekt | Opis |
---|---|
SWIPE_DIRECTION |
Może to być TOP_TO_BOTTOM , BOTTOM_TO_TOP , LEFT_TO_RIGHT lub RIGHT_TO_LEFT . |
SWIPE_FRACTION |
Wykonaj jedną z tych czynności:
|
NUMBER_OF_STEPS |
Liczba kroków, które mają być wykonane podczas przesuwania. Zobacz
segmentSteps .
|
Tworzenie i wykonywanie
Framework Spectatio jest automatycznie kompilowany w ramach pliku APK testowego. Aby skompilować testowy plik APK, kod źródłowy AOSP musi znajdować się na lokalnej stacji roboczej. Po skompilowaniu testowego pliku APK użytkownik musi zainstalować go na urządzeniu i przeprowadzić test.
Poniższy przykładowy kod pokazuje kompilowanie, instalowanie i uruchamianie 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, która ma zostać przetestowana. Na przykład ustaw TEST-APK-NAME na
AndroidAutomotiveSettingsTests
, aby przetestować ustawienia Wi-Fi zgodnie z tym, co jest określone w plikuAndroid.bp
. Nazwa pliku APK znajduje się w odpowiednim plikuAndroid.bp
testu motoryzacyjnego.DEVICE-SERIAL: numer seryjny DUT. Ten parametr nie jest wymagany, jeśli z hostem połączone jest tylko jedno urządzenie.
config-file-path
: opcjonalny parametr wymagany tylko do udostępniania niestandardowych konfiguracji interfejsu użytkownika urządzenia zgodnie z opisem w pliku konfiguracji JSON. Jeśli nie podasz wartości, framework użyje wartości domyślnych do wykonania testów.PATH-FOR-BUILT-TEST-APK: ścieżka, na której budowany jest testowy plik APK, gdy wykonywane jest polecenie
make
.TEST-PACKAGE: nazwa pakietu testowego.
TEST-CLASSNAME: nazwa klasy testu. Na przykład w przypadku testu Ustawienia Wi-Fi pakiet testowy to
android.platform.tests
, a nazwa klasy testu toWifiSettingTest
.
Biblioteka fragmentów dotyczących motoryzacji
Automotive Snippet Library to zestaw bibliotek Android Test dla projektu Android Open Source (AOSP) zaprojektowanych do interakcji z aplikacją i usługami samochodowymi. Korzysta on z narzędzia Spectatio, które zapewnia wygodny mechanizm wykonywania wywołań procedur zdalnych (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.
- Konfiguracja środowiska AOSP z wymaganymi narzędziami do kompilacji.
- Urządzenie z Androidem Automotive (emulator lub urządzenie fizyczne) z dostępem do adb.
Kompilacja
Aby skompilować różne fragmenty kodu udostępnione przez Automotive Snippet Library, możesz użyć dostarczonego pliku android.bp
. Użyj poleceń z poprzedniej sekcji, aby skompilować plik APK.
Wdrażanie
Po skompilowaniu bibliotek fragmentów wdróż utworzone pliki APK na urządzeniu docelowym za pomocą polecenia adb install
wymienionego w poprzedniej sekcji.
Przeprowadzanie testów
Biblioteki fragmentów kodu udostępniają kilka metod RPC do interakcji z systemem samochodowym. Te metody można wywołać za pomocą frameworka Mobly z maszyny 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ł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 masz podłączone większą liczbę urządzeń.
Uwzględnione biblioteki
Biblioteka fragmentów kodu dla branży motoryzacyjnej zawiera te biblioteki fragmentów kodu i elementy pomocnicze:
AutomotiveSnippet: udostępnia interfejsy API związane z obsługą pojazdu, takie jak wybieranie numerów, sterowanie głośnością, przyciski w samochodzie i interakcje 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 kodu Automotive i fragment kodu PhoneSnippet mają wspólną logikę.
W szczególności możesz w ten sposób wkradać się do wywołań RCP związanych z Bluetooth, aby sparować urządzenie samochodowe z telefonem. Więcej informacji znajdziesz w artykule bt_discovery_test
.
- TEST-CLASSNAME: nazwa klasy testu. Na przykład w przypadku testu Ustawienia Wi-Fi pakiet testu to
android.platform.tests
, a nazwa klasy testu toWifiSettingTest
.