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 AAOS oraz jego aplikacji.
Projektowanie ogólne
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 wirtualizowanych ś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 aplikacjami użytkownika i systemowymi 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 do konkretnych 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 zapewniają takie funkcje, 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 elementy pomocnicze przeznaczone dla konkretnych aplikacji, jednocześnie rozszerzając istniejącą standardową klasę pomocniczą i importując klasy pomocnicze.
Rysunek 2 przedstawia ogólną architekturę platformy Spectatio i wszystkie podmioty zaangażowane w implementację interfejsów API do testowania aplikacji.
Rysunek 2. Architektura ogólna platformy Spectatio
Interfejs pomocy w aplikacji zawiera szablon implementacji pomocy w aplikacji. 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 oraz listę funkcji interfejsu znajdziesz w artykule o funkcjach interfejsu Asystenta 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
.
Platforma używa klas pomocniczych narzędzi. Na przykład AutoJsonUtility.java
jest klasą narzędziową, która wczytuje plik konfiguracji JSON danego urządzenia i aktualizuje konfiguracje platformy w czasie działania.
Moduł implementacji pomocy aplikacji jest podstawą platformy Spectatio. Zawiera on implementację funkcji pomocniczych zdefiniowanych w interfejsie 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 Automotive do testowania aplikacji. Więcej informacji i listę implementacji znajdziesz w funkcjach implementacji pomocy aplikacji w AOSP.
Testy motoryzacyjne korzystają z funkcji implementacji pomocy aplikacji, aby testować różne operacje związane z aplikacją. Aby uzyskać dostęp do funkcji implementacji pomocy aplikacji, użyj klasy HelperAccessor
.
Poniżej znajduje się kod, który przedstawia konfigurację, czyszczenie i wykonanie przykładowego testu motoryzacyjnego.
@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ć do 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 pliku konfiguracji JSON w czasie wykonywania, aby wprowadzać na urządzeniu zmiany interfejsu 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: identyfikator seryjny urządzenia pokładowego (DUT). Ten parametr nie jest wymagany, jeśli z hostem połączone jest tylko jedno urządzenie.
PATH-TO-JSON-FILE: ścieżka pliku JSON na hoście.
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ć napisana na tyle specjalnie, by w odpowiednim kontekście zawężała się do jednego elementu.
TEKST
Jest to najprostszy typ elementu interfejsu. Element interfejsu użytkownika jest identyfikowany na podstawie tekstu 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 wyrażenie VALUE
musi się tylko pojawić w tekście elementu, do którego ma być dopasowane.
"PRIVACY_CALENDAR": {
"TYPE": "TEXT_CONTAINS",
"VALUE": "Calendar"
}
OPIS
Identyfikować element za pomocą atrybutu opisu treści, wymagając dokładnego dopasowania.
"APP_GRID_SCROLL_BACKWARD_BUTTON": {
"TYPE": "DESCRIPTION",
"VALUE": "Scroll up"
}
IDENTYFIKATOR_ZASOBU
Identyfikuj element według jego identyfikatora zasobu, opcjonalnie sprawdzając też komponent pakietu tego identyfikatora. Klucz PACKAGE
jest opcjonalny. W przypadku jego pominięcia dowolny pakiet będzie dopasowywany i tylko część identyfikatora po :id/
będzie brana pod uwagę.
"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. Zazwyczaj należy ich używać w elemencie MULTIPLE
, aby zawężać zakres innego typu elementów. Klucz FLAG
jest opcjonalny i domyślnie ma wartość true
.
"SAMPLE_ELEMENT": {
"TYPE": "CLICKABLE",
"FLAG": false
}
CLASS
Identyfikuj element na podstawie jego klasy.
"SECURITY_SETTINGS_ENTER_PASSWORD": {
"TYPE": "CLASS",
"VALUE": "android.widget.EditText"
}
HAS_ANCESTOR
Aby go zidentyfikować, sprawdź hierarchię widżetów na poziomie ich przodków. 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 wskazuje obiekt podrzędny do wyszukania. Klucz DEPTH
określa, jak daleko w hierarchii należy się patrzeć. 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
, zawierający 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żde działanie ma NAME
, TYPE
, (zwykle) CONFIG
, a czasami SWIPE_CONFIG
lub SCROLL_CONFIG
. W przypadku większości typów TYPE CONFIG
jest obiektem z kluczem UI_ELEMENT
, którego wartość ma taką samą postać jak wpis elementu interfejsu (patrz wyżej). Typy:
PRESS LONG_PRESS CLICK LONG_CLICK CLICK_IF_EXIST |
HAS_UI_ELEMENT_IN_FOREGROUND PRZEWIŃ_DO_ZNAJDŹ_ORAZ_KLIKNIĘCIE SCROLL_TO_FIND_AND_CLICK_IF_EXIST PRZEWIŃ_TO_ZNAJDŹ_ORAZ_KLIKNIJ SSTORAGE_TO_FIND_AND_KLIKNIJ_IF_EXIST |
W przypadku innych typów szczegóły konfiguracji to:
Obiekt | Opis |
---|---|
COMMAND |
Obiekt z wartością TEXT zawierającą polecenie do wykonania. |
HAS_PACKAGE_IN_FOREGROUND |
Obiekt z wartością TEXT zawierający pakiet. |
SWIPE |
Pomiń CONFIG key w przypadku działania SWIPE . Wykorzystuje 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:
PRZEWIŃ_KONFIGURACJĘ
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. Obiekt ma tę samą formę co konfiguracja elementu interfejsu (patrz wyż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 rozpoczęcia i zatrzymania przeciągania, po którym zostanie przewijane (opcjonalne, wartość domyślna = 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,wartość domyślna = 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
Platforma Spectatio jest tworzona automatycznie jako część testowego pakietu APK. 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 danymi w plikuAndroid.bp
. Nazwę pakietu APK znajdziesz w odpowiednim plikuAndroid.bp
dotyczącym testu samochodowego.DEVICE-SERIAL: numer seryjny DUT. Ten parametr nie jest wymagany, jeśli z hostem jest połączone 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 tworzenia testowego pakietu APK po wykonaniu polecenia
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 samochodowego zawiera następujące biblioteki fragmentów i funkcje 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 wtrącać się w wywołania RCP związane 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 sieci Wi-Fi pakiet testowy to
android.platform.tests
, a nazwa klasy testowej toWifiSettingTest
.