Spectatio es un marco de prueba de código abierto desarrollado para probar el sistema operativo Android Automotive (AAOS) en dispositivos reales y virtuales. Spectatio proporciona API para probar aplicaciones en un dispositivo automotriz y es una solución extensible y escalable que se utiliza para verificar la capacidad y el rendimiento de AAOS y sus aplicaciones.
Diseño de alto nivel
El marco Spectatio es adaptable y ampliable para varias implementaciones de UI de AAOS. Se utiliza para probar la capacidad y el rendimiento de AAOS en el hardware del dispositivo, emuladores y entornos virtualizados.
La siguiente figura explica el diseño de alto nivel del marco Spectatio.
Figura 1. Diseño de alto nivel del marco Spectatio.
Construido sobre UI Automator , el marco Spectatio proporciona un conjunto de API para crear pruebas de UI que interactúan con las aplicaciones del usuario y del sistema en AAOS. Las pruebas automotrices utilizan las API proporcionadas por el marco Spectatio para las pruebas, lo que hace que estas pruebas sean independientes del dispositivo bajo prueba (DUT) y escalables para probar varios dispositivos, si son compatibles.
La Figura 1 muestra que el marco Spectatio está modularizado en función de aplicaciones de referencia como Dialer, Medicenter y Settings utilizando interfaces y ayudantes específicos de la aplicación, lo que lo hace fácilmente extensible para nuevas aplicaciones. El marco Spectatio reutiliza las clases auxiliares estándar y de utilidad comunes. La clase auxiliar estándar es la clase principal para todas las funciones auxiliares de la aplicación y proporciona funciones estándar que son específicas del dispositivo o aplicables a todas las aplicaciones. Las clases de ayuda de utilidades proporcionan utilidades como leer o escribir archivos desde el dispositivo.
Arquitectura
Para proporcionar un conjunto de API para crear pruebas de UI, el marco Spectatio implementa interfaces y asistentes específicos de la aplicación mientras extiende la clase auxiliar estándar existente e importa las clases auxiliares de utilidad.
La Figura 2 ilustra la arquitectura de alto nivel del marco Spectatio y todas las entidades involucradas en la implementación de API para probar una aplicación.
Figura 2. Arquitectura de alto nivel del marco Spectatio.
La interfaz de la aplicación auxiliar proporciona un modelo para la implementación de una aplicación auxiliar. Consta de varias funciones auxiliares necesarias para probar aplicaciones. Cada aplicación tiene su propia interfaz, como IAutoSettingHelper
y IAutoDialHelper
. Para obtener más información y una lista de funciones de la interfaz, consulte las funciones de la interfaz auxiliar de la aplicación en AOSP.
La clase de ayuda estándar consta de atributos y funciones estándar que se requieren para la configuración del dispositivo pero que no son específicos de ninguna aplicación, como pressHome
y scroll
. La clase auxiliar estándar se define en AbstractAutoStandardAppHelper.java
.
El marco utiliza las clases auxiliares de utilidad . Por ejemplo, AutoJsonUtility.java
es una clase de utilidad que carga el archivo de configuración JSON del dispositivo determinado y actualiza las configuraciones del marco en tiempo de ejecución.
El módulo de implementación de la aplicación auxiliar es el núcleo del marco Spectatio. Contiene la implementación de las funciones auxiliares definidas en la interfaz auxiliar de la aplicación, que son necesarias para probar aplicaciones en un dispositivo automotriz. Cada aplicación tiene su propia implementación, como SettingHelperImpl
y DialHelperImpl
, utilizadas por las pruebas de Automoción para probar las aplicaciones. Para obtener más información y una lista de implementaciones, consulte las funciones de implementación de la aplicación auxiliar en AOSP.
Las pruebas automotrices utilizan las funciones de implementación auxiliares de la aplicación para probar varias operaciones relacionadas con la aplicación. Utilice la clase HelperAccessor
para obtener acceso a las funciones de implementación del asistente de la aplicación.
El siguiente código muestra la configuración, limpieza y ejecución de una prueba automotriz de muestra.
@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());
}
}
Personalización
El marco Spectatio es independiente de la interfaz de usuario del dispositivo, por lo que es escalable para probar dispositivos con diversas interfaces de usuario y hardware. Para lograr esta escalabilidad, Spectatio utiliza configuraciones de dispositivo predeterminadas basadas en el dispositivo de referencia. Para admitir configuraciones de dispositivos no predeterminadas, el marco utiliza un archivo de configuración JSON en tiempo de ejecución para establecer los cambios de UI deseados para el dispositivo. Un archivo de configuración JSON admite elementos de la interfaz de usuario como TEXT
, DESCRIPTION
y RESOURCE_ID
, junto con configuraciones path
y debe contener solo información sobre los cambios de la interfaz de usuario para el DUT. El resto de los elementos de la interfaz de usuario utilizan los valores de configuración predeterminados proporcionados en el marco.
Configuraciones de dispositivo predeterminadas
El siguiente archivo de configuración JSON de muestra muestra las configuraciones de dispositivos disponibles y sus valores predeterminados.
Haga clic aquí para mostrar un archivo de configuración JSON de muestra
{ "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" } } } }
Configuraciones de dispositivos alternativas
El siguiente ejemplo de código muestra un ejemplo del archivo de configuración JSON donde la configuración del DUT anula la configuración predeterminada. En este ejemplo:
Las configuraciones de Internet se denominan Red e Internet en los dispositivos de referencia y Conectividad en el DUT.
La configuración de fecha y hora está disponible en Configuración > Fecha y hora para dispositivos de referencia y en Configuración > Sistema > Fecha y hora para el DUT.
// 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"
},
....
}
Cuando el archivo de configuración JSON está listo, se proporciona en tiempo de ejecución como se muestra en el siguiente bloque de código:
# Push The JSON configuration file to the device
adb -s DEVICE-SERIAL push PATH-OF-JSON-FILE /data/local/tmp/runtimeSpectatioConfig.json
En este comando:
DEVICE-SERIAL : ID de serie del DUT. Este parámetro no es necesario si solo hay un dispositivo conectado al host.
PATH-TO-JSON-FILE : Ruta del archivo JSON en la máquina host.
Formato de configuración
Hay cinco objetos de nivel superior en la configuración, con las siguientes claves y valores:
Objeto | Descripción |
---|---|
PACKAGES | Un objeto que describe el paquete principal de varias aplicaciones, que se utilizan para determinar cuándo esa aplicación está en primer plano. |
ACTIONS | Un objeto que indica tipos de acción y parámetros para varias acciones. Por ejemplo, si utilizar botones o un gesto para desplazarse. |
COMMANDS | Un objeto que especifica comandos que realizan varias acciones. |
UI_ELEMENTS | Un objeto utilizado para construir UI Automator `BySelectors` que selecciona elementos de UI (descrito en detalle a continuación). |
WORKFLOWS | Secuencias de acciones que logran tareas de alto nivel (descritas en detalle a continuación). |
elementos de la interfaz de usuario
Cada elemento de la interfaz de usuario tiene un TYPE
que especifica qué buscará UI Automator para identificar el elemento (como ID de recurso, texto y descripción) y los valores de configuración asociados con ese tipo. En general, cada vez que un asistente identifica un elemento en la pantalla usando esta configuración, obtiene exactamente un elemento. Si varios elementos coinciden con la configuración, se utiliza uno arbitrario en la prueba. Por lo tanto, la configuración debe (generalmente) escribirse de manera lo suficientemente específica como para limitarse a un elemento en el contexto relevante.
TEXTO
Este es el tipo de elemento de interfaz de usuario más simple. El elemento de la interfaz de usuario se identifica por su texto y requiere una coincidencia exacta.
"CALL_HISTORY_MENU": {
"TYPE": "TEXT",
"VALUE": "Recents"
}
TEXTO_CONTIENE
Igual que TEXT
, excepto que el VALUE
especificado solo necesita aparecer en algún lugar del texto del elemento que se va a comparar.
"PRIVACY_CALENDAR": {
"TYPE": "TEXT_CONTAINS",
"VALUE": "Calendar"
}
DESCRIPCIÓN
Identifique el elemento por su atributo de descripción de contenido, lo que requiere una coincidencia exacta.
"APP_GRID_SCROLL_BACKWARD_BUTTON": {
"TYPE": "DESCRIPTION",
"VALUE": "Scroll up"
}
RECURSO_ID
Identifique el elemento por su ID de recurso y, opcionalmente, también verifique el componente del paquete de ese ID. La clave PACKAGE
es opcional; si se omite, cualquier paquete coincidirá y solo se considerará la parte del ID que sigue a :id/
.
"APP_LIST_SCROLL_ELEMENT": {
"TYPE": "RESOURCE_ID",
"VALUE": "apps_grid",
"PACKAGE": "com.android.car.carlauncher"
}
CLICABLE, DESPLAZABLE
Identifique el elemento en función de si se puede hacer clic o desplazarse (o no). Estos son tipos de elementos muy amplios y, por lo general, solo deben usarse en MULTIPLE
para ayudar a delimitar otro tipo de elemento. La clave FLAG
es opcional y su valor predeterminado es true
.
"SAMPLE_ELEMENT": {
"TYPE": "CLICKABLE",
"FLAG": false
}
CLASE
Identificar el elemento según su clase.
"SECURITY_SETTINGS_ENTER_PASSWORD": {
"TYPE": "CLASS",
"VALUE": "android.widget.EditText"
}
TIENE_ANCESTOR
Identifique el elemento buscando en la jerarquía de widgets sus antepasados. La clave ANCESTOR
contiene un objeto que identifica al antepasado. La clave DEPTH
especifica hasta qué punto se debe buscar en la jerarquía. DEPTH
es opcional y tiene un valor predeterminado de 1
.
"SAMPLE_ELEMENT": {
"TYPE": "HAS_ANCESTOR",
"DEPTH": 2,
"ANCESTOR": {
"TYPE": "CLASS",
"VALUE": "android.view.ViewGroup"
}
}
HAS_DESCENDANTE
Identifique el elemento mirando hacia abajo en la jerarquía a sus hijos. La clave DESCENDANT
contiene un objeto que especifica el niño a buscar. La clave DEPTH
especifica hasta qué punto se debe buscar en la jerarquía. DEPTH
es opcional y tiene un valor predeterminado de 1
.
"SAMPLE_ELEMENT": {
"TYPE": "HAS_DESCENDANT",
"DEPTH": 2,
"DESCENDANT": {
"TYPE": "CLASS",
"VALUE": "android.view.ViewGroup"
}
}
MÚLTIPLE
Identificar el elemento basándose en múltiples condiciones simultáneas, todas las cuales deben cumplirse.
"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"
}
}
]
}
En este ejemplo, la configuración identifica un RelativeLayout
que tiene un descendiente en la profundidad 2
, que tiene el texto Permission manager
.
Flujos de trabajo
Un flujo de trabajo representa una secuencia de acciones utilizadas para realizar una tarea particular, que puede diferir bastante de un tipo de dispositivo a otro y es más flexible de representar en la configuración que en el código.
"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"
}
}
}
]
}
Cada flujo de trabajo es un par clave-valor donde la clave es el nombre del flujo de trabajo y el valor es una serie de acciones a realizar. Cada acción tiene un NAME
, un TYPE
, (normalmente) un CONFIG
y (a veces) un SWIPE_CONFIG
o SCROLL_CONFIG
. Para la mayoría de los TYPE, CONFIG
es un objeto con una clave UI_ELEMENT
cuyo valor toma la misma forma que una entrada de elemento UI (ver arriba). Esos TIPOS son:
PRENSA PULSACIÓN LARGA HACER CLIC CLIC LARGO HAGA CLIC_SI_EXISTE | HAS_UI_ELEMENT_IN_FOREGROUND SCROLL_TO_FIND_AND_CLICK SCROLL_TO_FIND_AND_CLICK_IF_EXIST DESLIZA_PARA_BUSCAR_Y_CLIC DESLIZAR_TO_FIND_AND_CLICK_IF_EXIST |
Para los demás TIPOS, los detalles de configuración son:
Objeto | Descripción |
---|---|
COMMAND | Un objeto con un valor TEXT que contiene el comando a ejecutar. |
HAS_PACKAGE_IN_FOREGROUND | Un objeto con un valor TEXT que contiene el paquete. |
SWIPE | Omita la CONFIG key para una acción SWIPE . Esto usa solo SWIPE_CONFIG |
WAIT_MS | Un objeto con un valor TEXT que contiene el número de milisegundos a esperar. |
Las acciones relacionadas con desplazarse y deslizar requieren una configuración adicional, como se muestra a continuación:
SCROLL_CONFIG
Objeto | Descripción |
---|---|
SCROLL_ACTION | Ya sea USE_GESTURE o USE_BUTTON |
SCROLL_DIRECTION | Ya sea HORIZONTAL o VERTICAL |
SCROLL_ELEMENT | Un objeto que indica el contenedor para desplazarse, utilizando el mismo formulario que una configuración de elemento de interfaz de usuario (ver arriba). |
SCROLL_FORWARD , SCROLL_BACKWARD | Los botones de desplazamiento hacia adelante y hacia atrás (obligatorios cuando SCROLL_ACTION es USE_BUTTON ). |
SCROLL_MARGIN | Si SCROLL_ACTION es USE_GESTURE , la distancia desde el borde del contenedor para iniciar y detener el arrastre que se utilizará para realizar el desplazamiento ( opcional, predeterminado = 10). |
SCROLL_WAIT_TIME | Si SCROLL_ACTION es USE_GESTURE , el tiempo en milisegundos que se debe esperar entre los gestos de desplazamiento al buscar un objeto en el que hacer clic. ( Opcional, predeterminado = 1). |
DESLIZAR_CONFIG
Objeto | Descripción |
---|---|
SWIPE_DIRECTION | Ya sea TOP_TO_BOTTOM , BOTTOM_TO_TOP , LEFT_TO_RIGHT o RIGHT_TO_LEFT |
SWIPE_FRACTION | Uno de los siguientes:
|
NUMBER_OF_STEPS | El número de pasos que se utilizarán para realizar el deslizamiento. Consulte segmentSteps . |
Construir y ejecutar
El marco Spectatio se crea automáticamente como parte del APK de prueba. Para crear el APK de prueba, el código base de AOSP debe residir en la estación de trabajo local. Una vez creado el APK de prueba, el usuario debe instalarlo en el dispositivo y ejecutar la prueba.
El siguiente ejemplo de código muestra la creación, instalación y ejecución de un APK de prueba.
# 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
En estos comandos:
TEST-APK-NAME : el nombre de la aplicación que se va a probar. Por ejemplo, configure TEST-APK-NAME en
AndroidAutomotiveSettingsTests
para probar la configuración de Wi-Fi como se especifica en el archivoAndroid.bp
. El nombre del APK se puede encontrar en el archivoAndroid.bp
correspondiente a la prueba Automotive .DEVICE-SERIAL : El ID de serie del DUT. Este parámetro no es necesario si solo hay un dispositivo conectado al host.
config-file-path
: parámetro opcional que solo se requiere para proporcionar configuraciones de IU del dispositivo no predeterminadas, como se especifica en el archivo de configuración JSON . Si no se proporcionan, el marco utiliza valores predeterminados para ejecutar las pruebas.PATH-FOR-BUILT-TEST-APK : la ruta donde se crea el APK de prueba cuando se ejecuta el comando
make
.TEST-PACKAGE : El nombre del paquete de prueba.
TEST-CLASSNAME : el nombre de la clase de prueba. Por ejemplo, para la prueba de configuración de Wifi , el paquete de prueba es
android.platform.tests
y el nombre de la clase de prueba esWifiSettingTest
.
Biblioteca de fragmentos de automoción
La biblioteca de fragmentos de automoción es un conjunto de bibliotecas de prueba de Android para el proyecto de código abierto de Android (AOSP) diseñadas para interactuar con aplicaciones y servicios de automoción. Aprovecha Spectatio con un mecanismo conveniente para ejecutar llamadas a procedimientos remotos (RPC) desde una máquina host (de prueba) a un dispositivo con Android.
Empezar
Antes de comenzar, revise estas secciones.
Requisitos previos
- Python 3.x instalado en la máquina host.
- Configuración del entorno AOSP con las herramientas de compilación necesarias.
- Un dispositivo automotriz Android (emulador o dispositivo físico) con acceso adb.
Compilacion
Para compilar los distintos fragmentos proporcionados por la biblioteca de fragmentos de automoción, puede utilizar el archivo android.bp
proporcionado. Siguiendo los comandos de la sección anterior para compilar el APK.
Despliegue
Después de compilar con éxito las bibliotecas de fragmentos, implemente los APK resultantes en el dispositivo de destino utilizando el comando adb install
mencionado en la sección anterior.
Ejecutar pruebas
Las bibliotecas de fragmentos exponen varios métodos RPC para interactuar con el sistema automotriz. Estos métodos se pueden invocar a través del marco Mobly desde la máquina host. Suponiendo que tiene configurado el entorno de prueba de Mobly, puede usar el script snippet_shell.py
para abrir un shell de Python interactivo, donde puede invocar manualmente los métodos RPC en el dispositivo. Ejemplo de invocación:
python3 snippet_shell.py com.google.android.mobly.snippet.bundled -s <serial>
Reemplace <serial>
con el número de serie del dispositivo, que puede obtener con dispositivos adb si hay varios dispositivos conectados.
Bibliotecas incluidas
La biblioteca de fragmentos de automoción incluye las siguientes bibliotecas de fragmentos y ayudas:
AutomotiveSnippet: proporciona API relacionadas con las operaciones del vehículo, como marcación, control de volumen, teclas físicas del vehículo e interacción con el centro multimedia.
PhoneSnippet: proporciona API relacionadas con la telefonía, incluido el manejo de llamadas, la exploración de contactos y las operaciones de SMS.
El fragmento Automotive y el PhoneSnippet comparten una lógica común. Específicamente, puede invadir llamadas RCP relacionadas con Bluetooth para emparejar un automóvil y un dispositivo telefónico. Este bt_discovery_test
muestra cómo.
- TEST-CLASSNAME : el nombre de la clase de prueba. Por ejemplo, para la prueba de configuración de Wifi , el paquete de prueba es
android.platform.tests
y el nombre de la clase de prueba esWifiSettingTest
.