Spectatio ist ein Open-Source-Testframework, das für das Testen von Android Automotive OS (AAOS) auf echten und virtuellen Geräten entwickelt wurde. Spectatio bietet APIs zum Testen von Apps auf einem Automotive-Gerät und ist eine erweiterbare und skalierbare Lösung zum Überprüfen der Funktionen und Leistung von AAOS und seinen Apps.
High-Level-Design
Das Spectatio-Framework ist anpassbar und erweiterbar für verschiedene AAOS-UI-Implementierungen. Es wird zum Testen der Funktionen und Leistung von AAOS auf Gerätehardware, Emulatoren und virtualisierten Umgebungen verwendet.
Die folgende Abbildung zeigt das High-Level-Design des Spectatio-Frameworks.
Abbildung 1 : High-Level-Design des Spectatio-Frameworks.
Das Spectatio-Framework basiert auf UI Automator und bietet eine Reihe von APIs zum Erstellen von UI-Tests, die mit Nutzer- und System-Apps auf AAOS interagieren. Automotive-Tests verwenden die APIs des Spectatio-Frameworks zum Testen. Dadurch sind diese Tests unabhängig vom zu testenden Gerät (Device Under Test, DUT) und können zum Testen verschiedener Geräte skaliert werden, sofern dies unterstützt wird.
Abbildung 1 zeigt, dass das Spectatio-Framework basierend auf Referenz-Apps wie Dialer, Medicenter und Einstellungen mit app-spezifischen Schnittstellen und Hilfsmethoden modularisiert ist. Dadurch lässt es sich problemlos für neue Apps erweitern. Das Spectatio-Framework verwendet die gängigen Standard- und Dienstprogramm-Hilfsklassen wieder. Die Standard-Hilfsklasse ist die übergeordnete Klasse für alle App-Hilfsfunktionen und bietet Standardfunktionen, die gerätespezifisch oder für alle Apps anwendbar sind. Die Dienstprogramm-Hilfsklassen bieten Dienstprogramme wie das Lesen oder Schreiben von Dateien vom Gerät.
Architektur
Um eine Reihe von APIs zum Erstellen von UI-Tests bereitzustellen, implementiert das Spectatio-Framework app-spezifische Schnittstellen und Hilfsmethoden, erweitert die vorhandene Standard-Hilfsklasse und importiert die Dienstprogramm-Hilfsklassen.
Abbildung 2 zeigt die High-Level-Architektur des Spectatio-Frameworks und alle Entitäten, die an der Implementierung von APIs zum Testen einer App beteiligt sind.
Abbildung 2 : High-Level-Architektur des Spectatio-Frameworks.
Die App-Hilfsschnittstelle bietet eine Vorlage für die Implementierung einer App-Hilfsmethode. Sie besteht aus verschiedenen Hilfsfunktionen, die zum Testen von Apps erforderlich sind. Jede App hat eine eigene Schnittstelle, z. B. IAutoSettingHelper
und IAutoDialHelper.
Weitere Informationen und eine Liste der Schnittstellenfunktionen finden Sie unter den App-Hilfsschnittstellenfunktionen in AOSP.
Die Standard-Hilfsklasse besteht aus Standardattributen und ‑funktionen, die für die Geräteeinrichtung erforderlich sind, aber nicht app-spezifisch sind, z. B. pressHome und scroll. Die Standard-Hilfsklasse ist in AbstractAutoStandardAppHelper.java definiert.
Die Dienstprogramm-Hilfsklassen werden vom Framework verwendet. For
example, AutoJsonUtility.java ist eine
Dienstprogrammklasse, die die angegebene JSON-Konfigurationsdatei des Geräts lädt und die
Framework-Konfigurationen zur Laufzeit aktualisiert.
Das Modul zur Implementierung der App-Hilfsmethode ist das Herzstück des Spectatio-Frameworks. Es enthält die Implementierung für die in der App-Hilfsschnittstelle definierten Hilfsfunktionen, die zum Testen von Apps auf einem Automotive-Gerät erforderlich sind. Jede App hat eine eigene Implementierung, z. B. SettingHelperImpl
und
DialHelperImpl,
die von
den Automotive-Tests zum Testen der Apps verwendet werden. Weitere Informationen und eine Liste der
Implementierungen finden Sie unter App-Hilfsimplementierungsfunktionen
'in AOSP.
Automotive-Tests
verwenden die Implementierungsfunktionen der App-Hilfsmethode, um verschiedene Vorgänge
im Zusammenhang mit der App zu testen. Verwenden Sie die Klasse HelperAccessor
, um auf die Implementierungsfunktionen der App-Hilfsmethode zuzugreifen.
Der folgende Code zeigt die Einrichtung, Bereinigung und Ausführung eines Automotive-Beispieltests.
@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());
}
}
Anpassung
Das Spectatio-Framework ist unabhängig von der Geräte-UI und kann daher zum Testen von Geräten mit unterschiedlichen UIs und Hardware skaliert werden. Um diese Skalierbarkeit zu erreichen, verwendet Spectatio Standardgerätekonfigurationen, die auf dem Referenzgerät basieren. Zur Unterstützung von nicht standardmäßigen Gerätekonfigurationen verwendet das Framework zur Laufzeit eine JSON-Konfigurationsdatei, um die gewünschten UI-Änderungen für das Gerät festzulegen. Eine JSON-Konfigurationsdatei unterstützt UI-Elemente wie TEXT, DESCRIPTION und RESOURCE_ID sowie path-Einstellungen und darf nur Informationen zu den UI-Änderungen für das DUT enthalten. Für die übrigen UI-Elemente werden die im Framework bereitgestellten Standardkonfigurationswerte verwendet.
Standardgerätekonfigurationen
Die folgende JSON-Beispielkonfigurationsdatei zeigt die verfügbaren Gerätekonfigurationen und ihre Standardwerte.
Klicken Sie hier, um eine JSON Beispielkonfigurationsdatei anzuzeigen
{ "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" } } } }
Alternative Gerätekonfigurationen
Das folgende Codebeispiel zeigt ein Beispiel für die JSON-Konfigurationsdatei, in der die Standardeinstellungen durch die Einstellungen auf dem DUT überschrieben werden. In diesem Beispiel gilt Folgendes:
Die Interneteinstellungen heißen auf Referenzgeräten Netzwerk &Internet und auf dem DUT Verbindung.
Die Einstellungen für Datum und Uhrzeit sind auf Referenzgeräten unter Einstellungen > Datum und Uhrzeit und auf dem DUT unter Einstellungen > System > Datum und Uhrzeit verfügbar.
// 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"
},
....
}
Wenn die JSON-Konfigurationsdatei fertig ist, wird sie zur Laufzeit bereitgestellt, wie im folgenden Codeblock gezeigt:
# Push The JSON configuration file to the device
adb -s DEVICE-SERIAL push PATH-OF-JSON-FILE /data/local/tmp/runtimeSpectatioConfig.json
Dabei gilt:
DEVICE-SERIAL: Serien-ID des DUT. Dieser Parameter ist nicht erforderlich, wenn nur ein Gerät mit dem Host verbunden ist.
PATH-TO-JSON-FILE: Pfad der JSON-Datei auf dem Hostcomputer.
Konfigurationsformat
Die Konfiguration enthält fünf Objekte der obersten Ebene mit den folgenden Schlüsseln und Werten:
| Objekt | Beschreibung |
|---|---|
PACKAGES |
Ein Objekt, das das Hauptpaket für verschiedene Apps beschreibt, mit dem ermittelt wird, wann sich die App im Vordergrund befindet. |
ACTIONS |
Ein Objekt, das Aktionstypen und Parameter für verschiedene Aktionen angibt. Beispielsweise, ob zum Scrollen Schaltflächen oder eine Touchgeste verwendet werden sollen. |
COMMANDS |
Ein Objekt, das Befehle angibt, mit denen verschiedene Aktionen ausgeführt werden. |
UI_ELEMENTS |
Ein Objekt, das zum Erstellen von UI Automator-`BySelectors` verwendet wird, mit denen UI Elemente ausgewählt werden (siehe unten). |
WORKFLOWS |
Sequenzen von Aktionen, mit denen übergeordnete Aufgaben ausgeführt werden (siehe unten). |
UI-Elemente
Jedes UI-Element hat einen TYPE, der angibt, wonach UI Automator suchen soll, um das Element zu identifizieren (z. B. Ressourcen-ID, Text und Beschreibung), sowie Konfigurationswerte, die mit diesem Typ verknüpft sind. Wenn eine Hilfsmethode mit dieser Konfiguration ein Element auf dem Bildschirm identifiziert, wird genau ein Element zurückgegeben. Wenn mehrere Elemente mit der Konfiguration übereinstimmen, wird ein beliebiges Element im Test verwendet. Daher sollte die Konfiguration (im Allgemeinen) so spezifisch sein, dass sie im relevanten Kontext auf ein Element beschränkt wird.
TEXT
Dies ist der einfachste UI-Elementtyp. Das UI-Element wird anhand seines Texts identifiziert und erfordert eine genaue Übereinstimmung.
"CALL_HISTORY_MENU": {
"TYPE": "TEXT",
"VALUE": "Recents"
}
TEXT_CONTAINS
Wie TEXT, mit dem Unterschied, dass der angegebene VALUE nur irgendwo im Text des Elements vorkommen muss, um eine Übereinstimmung zu erzielen.
"PRIVACY_CALENDAR": {
"TYPE": "TEXT_CONTAINS",
"VALUE": "Calendar"
}
BESCHREIBUNG
Identifizieren Sie das Element anhand des Attributs für die Inhaltsbeschreibung. Eine genaue Übereinstimmung ist erforderlich.
"APP_GRID_SCROLL_BACKWARD_BUTTON": {
"TYPE": "DESCRIPTION",
"VALUE": "Scroll up"
}
RESOURCE_ID
Identifizieren Sie das Element anhand seiner Ressourcen-ID und prüfen Sie optional auch die Paketkomponente dieser ID. Der Schlüssel PACKAGE ist optional. Wenn er weggelassen wird, stimmt jedes Paket überein und nur der Teil der ID nach :id/ wird berücksichtigt.
"APP_LIST_SCROLL_ELEMENT": {
"TYPE": "RESOURCE_ID",
"VALUE": "apps_grid",
"PACKAGE": "com.android.car.carlauncher"
}
CLICKABLE, SCROLLABLE
Identifizieren Sie das Element danach, ob es anklickbar oder scrollbar ist.
Dies sind sehr allgemeine Elementtypen, die in der Regel nur in einem MULTIPLE verwendet werden sollten, um einen anderen Elementtyp einzugrenzen. Der Schlüssel FLAG ist optional und hat standardmäßig den Wert true.
"SAMPLE_ELEMENT": {
"TYPE": "CLICKABLE",
"FLAG": false
}
CLASS
Identifizieren Sie das Element anhand seiner Klasse.
"SECURITY_SETTINGS_ENTER_PASSWORD": {
"TYPE": "CLASS",
"VALUE": "android.widget.EditText"
}
HAS_ANCESTOR
Identifizieren Sie das Element, indem Sie die Widget-Hierarchie nach seinen Vorgängern durchsuchen. Der Schlüssel ANCESTOR enthält ein Objekt, das den Vorgänger identifiziert. Der Schlüssel DEPTH gibt an, wie weit in der Hierarchie gesucht werden soll. DEPTH ist optional und hat den Standardwert 1.
"SAMPLE_ELEMENT": {
"TYPE": "HAS_ANCESTOR",
"DEPTH": 2,
"ANCESTOR": {
"TYPE": "CLASS",
"VALUE": "android.view.ViewGroup"
}
}
HAS_DESCENDANT
Identifizieren Sie das Element, indem Sie die Hierarchie nach seinen untergeordneten Elementen durchsuchen. Der Schlüssel DESCENDANT enthält ein Objekt, das das untergeordnete Element angibt, nach dem gesucht werden soll. Der Schlüssel DEPTH gibt an, wie weit in der Hierarchie gesucht werden soll. DEPTH ist optional und hat den Standardwert 1.
"SAMPLE_ELEMENT": {
"TYPE": "HAS_DESCENDANT",
"DEPTH": 2,
"DESCENDANT": {
"TYPE": "CLASS",
"VALUE": "android.view.ViewGroup"
}
}
MULTIPLE
Identifizieren Sie das Element anhand mehrerer gleichzeitiger Bedingungen, die alle erfüllt sein müssen.
"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"
}
}
]
}
In diesem Beispiel identifiziert die Konfiguration ein RelativeLayout mit einem untergeordneten Element in Tiefe 2, das den Text Permission manager enthält.
Workflows
Ein Workflow stellt eine Sequenz von Aktionen dar, die zum Ausführen einer bestimmten Aufgabe verwendet werden. Diese kann sich von Gerätetyp zu Gerätetyp erheblich unterscheiden und lässt sich in der Konfiguration flexibler darstellen als im Code.
"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"
}
}
}
]
}
Jeder Workflow ist ein Schlüssel/Wert-Paar, wobei der Schlüssel der Name des Workflows und der Wert ein Array von auszuführenden Aktionen ist. Jede Aktion hat einen NAME, einen TYPE,
(in der Regel) eine CONFIG und (manchmal) eine SWIPE_CONFIG oder SCROLL_CONFIG. Für die meisten TYPEs ist die CONFIG ein Objekt mit einem UI_ELEMENT-Schlüssel, dessen Wert dieselbe Form wie ein UI-Elementeintrag hat (siehe oben). Diese TYPEs sind:
| 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 |
Für die anderen TYPEs sind die Konfigurationsdetails:
| Objekt | Beschreibung |
|---|---|
COMMAND |
Ein Objekt mit einem TEXT-Wert, der den auszuführenden Befehl enthält. |
HAS_PACKAGE_IN_FOREGROUND |
Ein Objekt mit einem TEXT-Wert, der das Paket enthält. |
SWIPE |
Lassen Sie den CONFIG key für eine SWIPE Aktion weg. Hier
wird nur SWIPE_CONFIG verwendet. |
WAIT_MS |
Ein Objekt mit einem TEXT-Wert, der die Anzahl der
Millisekunden enthält, die gewartet werden soll. |
Für Scroll- und Wischaktionen ist eine zusätzliche Konfiguration erforderlich:
SCROLL_CONFIG
| Objekt | Beschreibung |
|---|---|
SCROLL_ACTION |
Entweder USE_GESTURE oder USE_BUTTON. |
SCROLL_DIRECTION |
Entweder HORIZONTAL oder VERTICAL. |
SCROLL_ELEMENT |
Ein Objekt, das den zu scrollenden Container angibt. Es hat dieselbe Form wie eine UI Elementkonfiguration (siehe oben). |
SCROLL_FORWARD, SCROLL_BACKWARD |
Die Schaltflächen zum Vorwärts- und Rückwärtsscrollen (erforderlich, wenn
SCROLL_ACTION auf USE_BUTTON gesetzt ist). |
SCROLL_MARGIN |
Wenn SCROLL_ACTION auf USE_GESTURE gesetzt ist, ist dies der Abstand
vom Rand des Containers, an dem das Ziehen gestartet und beendet wird, um zu scrollen (optional, Standardwert = 10). |
SCROLL_WAIT_TIME |
Wenn SCROLL_ACTION auf USE_GESTURE gesetzt ist, ist dies die Zeit in
Millisekunden, die zwischen den Scrollgesten gewartet wird, wenn nach einem anzuklickenden Objekt gesucht wird.
(Optional,Standardwert = 1). |
SWIPE_CONFIG
| Objekt | Beschreibung |
|---|---|
SWIPE_DIRECTION |
Entweder TOP_TO_BOTTOM, BOTTOM_TO_TOP,
LEFT_TO_RIGHT, oder RIGHT_TO_LEFT. |
SWIPE_FRACTION |
Einer der folgenden Werte:
|
NUMBER_OF_STEPS |
Die Anzahl der Schritte, die zum Ausführen der Wischgeste verwendet werden sollen. Siehe
segmentSteps.
|
Erstellen und ausführen
Das Spectatio-Framework wird automatisch als Teil des Test-APKs erstellt. Zum Erstellen des Test-APKs muss sich die AOSP-Codebasis auf der lokalen Workstation befinden. Nachdem das Test-APK erstellt wurde, muss der Nutzer das APK auf dem Gerät installieren und den Test ausführen.
Das folgende Codebeispiel zeigt das Erstellen, Installieren und Ausführen eines Test-APKs.
# 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
Dabei gilt:
TEST-APK-NAME: Der Name der zu testenden App. Setzen Sie beispielsweise TEST-APK-NAME auf
AndroidAutomotiveSettingsTests, um die WLAN-Einstellungen wie in der DateiAndroid.bpangegeben zu testen. Der Name des APKs ist in der jeweiligenAndroid.bpDatei für den Automotive-Test zu finden.DEVICE-SERIAL: Die Serien-ID des DUT. Dieser Parameter ist nicht erforderlich, wenn nur ein Gerät mit dem Host verbunden ist.
config-file-path: Optionaler Parameter, der nur erforderlich ist, um nicht standardmäßige Geräte-UI-Konfigurationen anzugeben, wie in der JSON-Konfigurationsdatei angegeben. Wenn er nicht angegeben wird, verwendet das Framework Standardwerte für die Ausführung der Tests.PATH-FOR-BUILT-TEST-APK: Der Pfad, in dem das Test-APK erstellt wird wenn der Befehl
makeausgeführt wird.TEST-PACKAGE: Der Name des Testpakets.
TEST-CLASSNAME: Der Name der Testklasse. Für den Test der WLAN-Einstellungen ist das Testpaket beispielsweise
android.platform.testsund der Name der TestklasseWifiSettingTest.
Automotive-Snippet-Bibliothek
Die Automotive-Snippet-Bibliothek ist eine Reihe von Android-Testbibliotheken für das Open-Source-Projekt für Android (AOSP), die für die Interaktion mit Automotive-Apps und ‑Diensten entwickelt wurden. Sie nutzt Spectatio mit einem praktischen Mechanismus zum Ausführen von Remoteprozeduraufrufen (Remote Procedure Calls, RPCs) von einem Hostcomputer (Testcomputer) zu einem Android-Gerät.
Jetzt starten
Lesen Sie zuerst die folgenden Abschnitte.
Vorbereitung
- Python 3.x auf dem Hostcomputer installiert.
- AOSP-Umgebung mit den erforderlichen Build-Tools eingerichtet.
- Ein Android Automotive-Gerät (Emulator oder physisches Gerät) mit ADB-Zugriff.
Compilation
Um die verschiedenen Snippets der Automotive-Snippet-Bibliothek zu kompilieren, können Sie die bereitgestellte Datei android.bp verwenden. Führen Sie die Befehle im vorherigen Abschnitt aus, um das APK zu kompilieren.
Bereitstellung
Nachdem Sie die Snippet-Bibliotheken erfolgreich kompiliert haben, stellen Sie die resultierenden APKs mit dem Befehl adb install aus dem vorherigen Abschnitt auf dem Zielgerät bereit.
Tests ausführen
Die Snippet-Bibliotheken stellen mehrere RPC-Methoden zur Interaktion mit dem Automotive-System bereit. Diese Methoden können über das Mobly-Framework vom Hostcomputer aus aufgerufen werden. Wenn Sie die Mobly-Testumgebung eingerichtet haben, können Sie mit dem
snippet_shell.py Skript eine interaktive Python-Shell öffnen, in der Sie
RPC-Methoden manuell auf dem Gerät aufrufen können. Beispielaufruf:
python3 snippet_shell.py com.google.android.mobly.snippet.bundled -s <serial>
Ersetzen Sie <serial> durch die Seriennummer des Geräts. Sie können sie mit
adb devices abrufen, wenn mehrere Geräte verbunden sind.
Enthaltene Bibliotheken
Die Automotive-Snippet-Bibliothek enthält die folgenden Snippet-Bibliotheken und Hilfsmethoden:
AutomotiveSnippet: Bietet APIs für Fahrzeugvorgänge wie Wählen, Lautstärkeregelung, Fahrzeugtasten und Interaktion mit dem Media Center.
PhoneSnippet: Bietet APIs für die Telefonie, einschließlich Anrufverwaltung, Kontaktsuche und SMS-Vorgänge.
Das Automotive-Snippet und das PhoneSnippet verwenden dieselbe Logik.
Insbesondere können Sie Bluetooth-bezogene RCP-Aufrufe verwenden, um ein Automotive-Gerät und ein Smartphone zu koppeln. Das bt_discovery_test zeigt, wie das geht.
- TEST-CLASSNAME: Der Name der Testklasse. Für den Test der
WLAN-Einstellungen ist
das Testpaket beispielsweise
android.platform.testsund der Name der TestklasseWifiSettingTest.