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 Fahrzeuggerät. Es ist eine erweiterbare und skalierbare Lösung, mit der die Funktionen und die Leistung von AAOS und seiner Apps überprüft werden.
Übergeordnetes Design
Das Spectatio-Framework ist anpassbar und erweiterbar für verschiedene AAOS-UI-Implementierungen. Es wird verwendet, um die Funktionen und die Leistung von AAOS auf Gerätehardware, Emulatoren und virtualisierten Umgebungen zu testen.
Die folgende Abbildung veranschaulicht das allgemeine Design des Spectatio-Frameworks.
Abbildung 1. Hochwertiges 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. Für Tests im Bereich Automotive werden die APIs des Spectatio-Frameworks verwendet. Dadurch sind diese Tests unabhängig vom Testgerät und skalierbar, um verschiedene Geräte zu testen, sofern unterstützt.
Abbildung 1 zeigt, dass das Spectatio-Framework auf der Grundlage von Referenz-Apps wie „Telefon“, „Medicenter“ und „Einstellungen“ mithilfe von app-spezifischen Oberflächen und Helfern modularisiert ist. Dadurch lässt es sich leicht 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 sind oder anwendungsübergreifend anwendbar sind. Die Hilfsklassen für Dienstprogramme bieten Dienstprogramme wie das Lesen oder Schreiben von Dateien auf dem Gerät.
Architektur
Um eine Reihe von APIs zum Erstellen von UI-Tests bereitzustellen, implementiert das Spectatio-Framework app-spezifische Schnittstellen und Helfer, erweitert die vorhandene Standard-Hilfeklasse und importiert die Dienstprogramm-Hilfeklassen.
In Abbildung 2 sehen Sie die allgemeine Architektur des Spectatio-Frameworks und alle Entitäten, die an der Implementierung von APIs zum Testen einer Anwendung beteiligt sind.
Abbildung 2: Gesamtarchitektur des Spectatio-Frameworks
Die App-Hilfsoberfläche enthält eine Vorlage für die Implementierung eines App-Hilfsprogramms. Es enthält verschiedene Hilfsfunktionen, die zum Testen von Apps erforderlich sind. Jede App hat eine eigene Benutzeroberfläche, z. B. IAutoSettingHelper
und IAutoDialHelper
.
Weitere Informationen und eine Liste der Schnittstellenfunktionen finden Sie in AOSP unter App Helper Interface Functions (App-Hilfsfunktionen für die Benutzeroberfläche).
Die Standard-Hilfsklasse besteht aus Standardattributen und ‑funktionen, die für die Geräteeinrichtung erforderlich sind, aber nicht für eine bestimmte App spezifisch sind, z. B. pressHome
und scroll
. Die Standard-Hilfsklasse ist in AbstractAutoStandardAppHelper.java
definiert.
Die Hilfsklassen werden vom Framework verwendet. AutoJsonUtility.java
ist beispielsweise eine Dienstprogrammklasse, die die angegebene JSON-Konfigurationsdatei des Geräts lädt und die Framework-Konfigurationen zur Laufzeit aktualisiert.
Das App Helper-Implementierungsmodul ist der Kern des Spectatio-Frameworks. Es enthält die Implementierung der in der App-Hilfsschnittstelle definierten Hilfsfunktionen, die zum Testen von Apps auf einem Automobilgerät erforderlich sind. Jede App hat eine eigene Implementierung, z. B. SettingHelperImpl
und DialHelperImpl
, die für die Tests der Apps verwendet werden. Weitere Informationen und eine Liste der Implementierungen finden Sie in AOSP unter App-Hilfe-Implementierungsfunktionen.
Bei Automotive-Tests werden die Implementierungsfunktionen des App-Hilfsprogramms verwendet, um verschiedene Vorgänge im Zusammenhang mit der App zu testen. Verwenden Sie die Klasse HelperAccessor
, um Zugriff auf die Implementierungsfunktionen des App-Hilfsprogramms zu erhalten.
Der folgende Code zeigt die Einrichtung, Bereinigung und Ausführung eines Beispieltests für die Automobilbranche.
@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());
}
}
Personalisierung
Das Spectatio-Framework ist unabhängig von der Geräte-UI und daher für das Testen von Geräten mit unterschiedlicher UI und Hardware skalierbar. 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 die Informationen zu den UI-Änderungen für die DUT enthalten. Die übrigen UI-Elemente verwenden die im Framework bereitgestellten Standardkonfigurationswerte.
Standardgerätekonfigurationen
Die folgende Beispiel-JSON-Konfigurationsdatei 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 des DUT überschrieben werden. In diesem Beispiel gilt Folgendes:
Die Interneteinstellungen heißen auf Referenzgeräten Netzwerk und Internet und auf dem DUT Konnektivität.
Die Datums- und Uhrzeiteinstellungen finden Sie für Referenzgeräte unter Einstellungen > Datum und Uhrzeit und für das DUT unter Einstellungen > System > Datum und Uhrzeit.
// 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"
},
....
}
Sobald 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
In diesem Befehl gilt:
DEVICE-SERIAL: Seriennummer des DUT. Dieser Parameter ist nicht erforderlich, wenn nur ein Gerät mit dem Host verbunden ist.
PATH-TO-JSON-FILE: Pfad zur 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 und anhand dessen ermittelt wird, wann diese App im Vordergrund ausgeführt wird. |
ACTIONS |
Ein Objekt, das Aktionstypen und Parameter für verschiedene Aktionen angibt. Beispielsweise, ob zum Scrollen Schaltflächen oder eine Geste verwendet werden sollen. |
COMMANDS |
Ein Objekt, das Befehle für verschiedene Aktionen angibt. |
UI_ELEMENTS |
Ein Objekt, mit dem UI Automator-„BySelectors“ (UI-Elemente auswählen) erstellt werden (siehe unten). |
WORKFLOWS |
Abfolgen von Aktionen, die allgemeine Aufgaben ausführen (siehe unten). |
UI-Elemente
Jedes UI-Element hat ein TYPE
, das angibt, wonach UI Automator suchen soll, um das Element zu identifizieren (z. B. Ressourcen-ID, Text und Beschreibung) und die mit diesem Typ verknüpften Konfigurationswerte. Im Allgemeinen wird bei der Identifizierung eines Elements auf dem Bildschirm mit dieser Konfiguration genau ein Element zurückgegeben. Wenn mehrere Elemente mit der Konfiguration übereinstimmen, wird im Test ein beliebiges Element verwendet. Daher sollte die Konfiguration (im Allgemeinen) so spezifisch formuliert sein, dass sie sich auf ein Element im relevanten Kontext eingrenzt.
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_ENTHÄLT
Entspricht TEXT
, mit der Ausnahme, dass das angegebene VALUE
nur irgendwo im Text des abzugleichenden Elements vorkommen muss.
"PRIVACY_CALENDAR": {
"TYPE": "TEXT_CONTAINS",
"VALUE": "Calendar"
}
BESCHREIBUNG
Das Element wird anhand des Attributs „content_description“ identifiziert. Es ist eine genaue Übereinstimmung 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 Sie ihn nicht angeben, 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"
}
ANKLICKBAR, SCROLLBAR
Identifizieren Sie das Element danach, ob es anklickbar oder scrollbar ist.
Dies sind sehr allgemeine Elementtypen und sollten im Allgemeinen nur in einem MULTIPLE
verwendet werden, um einen anderen Elementtyp einzugrenzen. Der Schlüssel FLAG
ist optional und standardmäßig 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
Ermitteln Sie das Element, indem Sie in der Widget-Hierarchie nach seinen Vorfahren suchen. Der Schlüssel ANCESTOR
enthält ein Objekt, das den übergeordneten Knoten identifiziert. Mit dem Schlüssel DEPTH
wird angegeben, wie weit oben 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
Suchen Sie in der Hierarchie nach den untergeordneten Elementen, um das Element zu identifizieren. Der Schlüssel DESCENDANT
enthält ein Objekt, das das zu suchende untergeordnete Element angibt. Mit dem Schlüssel DEPTH
wird angegeben, wie weit oben 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"
}
}
MEHRERE
Das Element wird anhand mehrerer gleichzeitiger Bedingungen identifiziert, 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 wird in der Konfiguration ein RelativeLayout
mit einem untergeordneten Element in der Tiefe 2
mit dem Text Permission manager
angegeben.
Workflows
Ein Workflow stellt eine Abfolge von Aktionen dar, die zur Ausführung einer bestimmten Aufgabe verwendet werden. Diese kann sich von Gerät zu Gerät unterscheiden und ist in der Konfiguration flexibler darstellbar 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 eine NAME
, eine TYPE
, (in der Regel) eine CONFIG
und (manchmal) eine SWIPE_CONFIG
oder SCROLL_CONFIG
. Bei den meisten TYPEs ist CONFIG
ein Objekt mit einem UI_ELEMENT
-Schlüssel, dessen Wert dieselbe Form wie ein UI-Elementeingabe hat (siehe oben). Diese TYPEs sind:
DRÜCKEN LANGE_DRÜCKEN KLICKEN LANGE_KLICKEN KLICKEN_WENN_VORHANDEN |
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 gelten folgende 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, das das Paket enthält. |
SWIPE |
Lassen Sie bei einer SWIPE -Aktion die CONFIG key aus. 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, mit demselben Formular wie bei der Konfiguration eines UI-Elements (siehe oben). |
SCROLL_FORWARD , SCROLL_BACKWARD |
Die Schaltflächen zum Scrollen nach vorne und hinten (erforderlich, wenn SCROLL_ACTION = USE_BUTTON ). |
SCROLL_MARGIN |
Wenn SCROLL_ACTION = USE_GESTURE ist, ist dies der Abstand vom Rand des Containers, ab dem das Ziehen zum Scrollen gestartet und beendet wird (optional, Standardwert = 10). |
SCROLL_WAIT_TIME |
Wenn SCROLL_ACTION USE_GESTURE ist, ist dies die Zeit in Millisekunden, die zwischen den Scroll-Gesten gewartet wird, wenn nach einem Objekt gesucht wird, auf das geklickt werden soll.
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 |
Eine der folgenden Optionen:
|
NUMBER_OF_STEPS |
Die Anzahl der Schritte, die für das Wischen verwendet werden sollen.
segmentSteps ansehen.
|
Erstellen und ausführen
Das Spectatio-Framework wird automatisch als Teil des Test-APK 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
In diesen Befehlen gilt:
TEST-APK-NAME: Der Name der zu testenden App. Legen Sie beispielsweise TEST-APK-NAME auf
AndroidAutomotiveSettingsTests
fest, um die WLAN-Einstellungen zu testen, die in der DateiAndroid.bp
angegeben sind. Den Namen des APK finden Sie in der entsprechendenAndroid.bp
-Datei für den Automobiltest.DEVICE-SERIAL: Die Seriennummer 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 keine angegeben werden, verwendet das Framework Standardwerte für die Ausführung der Tests.PATH-FOR-BUILT-TEST-APK: Der Pfad, unter dem das Test-APK erstellt wird, wenn der Befehl
make
ausgeführt wird.TEST-PACKAGE: Der Name des Testpakets.
TEST-CLASSNAME: Der Name der Testklasse. Für den Test WLAN-Einstellungen lautet das Testpaket beispielsweise
android.platform.tests
und der Name der TestklasseWifiSettingTest
.
Snippet-Bibliothek für die Automobilbranche
Die Automotive Snippet Library ist eine Reihe von Android-Testbibliotheken für das Android Open Source Project (AOSP), die für die Interaktion mit Apps und Diensten aus der Automobilbranche entwickelt wurden. Es nutzt Spectatio mit einem praktischen Mechanismus zur Ausführung von Remote Procedure Calls (RPCs) von einem Host- (Test-)Computer auf ein Android-Gerät.
Erste Schritte
Lesen Sie sich diese Abschnitte durch, bevor Sie beginnen.
Voraussetzungen
- Python 3.x auf dem Hostcomputer installiert
- AOSP-Umgebung mit den erforderlichen Build-Tools einrichten
- Ein Android Automotive-Gerät (Emulator oder physisches Gerät) mit ADB-Zugriff.
Compilation
Sie können die verschiedenen Snippets aus der Snippet-Bibliothek für die Automobilbranche mithilfe der bereitgestellten Datei android.bp
kompilieren. Führen Sie die Befehle im vorherigen Abschnitt aus, um das APK zu kompilieren.
Bereitstellung
Nachdem du die Snippet-Bibliotheken erfolgreich kompiliert hast, kannst du die resultierenden APKs mit dem im vorherigen Abschnitt erwähnten adb install
-Befehl auf dem Zielgerät bereitstellen.
Tests ausführen
Die Snippet-Bibliotheken bieten mehrere RPC-Methoden für die Interaktion mit dem Automobilsystem. Diese Methoden können über das Mobly-Framework vom Hostcomputer aufgerufen werden. Wenn Sie die Mobly-Testumgebung eingerichtet haben, können Sie mit dem Script snippet_shell.py
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 Snippet-Bibliothek für die Automobilbranche enthält die folgenden Snippet-Bibliotheken und ‑Hilfsprogramme:
AutomotiveSnippet: stellt APIs für Fahrzeugvorgänge wie Wähltasten, Lautstärkeregelung, feste Fahrzeugschlüssel und Interaktion mit dem Mediacenter bereit.
PhoneSnippet: Bietet telefonbezogene APIs, einschließlich Anrufverwaltung, Kontaktsuche und SMS-Vorgänge.
Das Snippet für die Automobilbranche und das PhoneSnippet haben einige gemeinsame Logik.
Insbesondere können Sie Bluetooth-bezogene RCP-Anrufe manipulieren, um ein Auto und ein Smartphone zu koppeln. bt_discovery_test
- TEST-CLASSNAME: Der Name der Testklasse. Für den Test WLAN-Einstellungen lautet das Testpaket beispielsweise
android.platform.tests
und der Name der TestklasseWifiSettingTest
.