O Spectatio é um framework de teste de código aberto desenvolvido para testar o Android Automotive OS (AAOS) em dispositivos reais e virtuais. O Spectatio fornece APIs para testar apps em um dispositivo automotivo e é uma solução extensível e escalonável usada para verificar a capacidade e o desempenho do AAOS e dos apps.
Design de alto nível
O framework Spectatio é adaptável e expansível para várias implementações de interface AAOS. Ele é usado para testar a capacidade e o desempenho do AAOS em hardware de dispositivos, emuladores e ambientes virtualizados.
A figura a seguir explica o design de alto nível do framework Spectatio.
Figura 1. Design de alto nível da estrutura Spectatio.
Criado com base no UI Automator, o framework Spectatio fornece um conjunto de APIs para criar testes de interface que interagem com apps do usuário e do sistema no AAOS. Os testes automotivos usam as APIs fornecidas pelo framework do Spectatio para testes, o que os torna independentes do dispositivo em teste (DUT, na sigla em inglês) e escalonáveis para testar dispositivos variados, se houver suporte.
A Figura 1 mostra que o framework Spectatio é modularizado com base em apps de referência como Discador, Medicenter e Configurações, usando interfaces e auxiliares específicos do app, o que facilita a extensão para novos apps. O framework Spectatio reutiliza as classes auxiliares padrão e utilitárias comuns. A classe auxiliar padrão é a classe mãe de todas as funções auxiliares do app e fornece funções padrão específicas do dispositivo ou aplicáveis a vários apps. As classes auxiliares de utilitários oferecem utilitários, como ler ou gravar arquivos no dispositivo.
Arquitetura
Para fornecer um conjunto de APIs para criar testes de interface, o framework Spectatio implementa interfaces e auxiliares específicos do app, estendendo a classe auxiliar padrão e importando as classes auxiliares de utilitários.
A Figura 2 ilustra a arquitetura de alto nível do framework do Spectatio e todas as entidades envolvidas na implementação de APIs para testar um app.
Figura 2. Arquitetura de alto nível do framework Spectatio.
A interface do App Helper fornece um modelo para a implementação de
um App Helper. Ele consiste em várias funções auxiliares que são necessárias
para testar apps. Cada app tem a própria interface, como IAutoSettingHelper
e IAutoDialHelper
.
Para mais informações e uma lista de funções de interface, consulte as funções de interface auxiliares do app no AOSP.
A classe auxiliar padrão consiste em atributos e funções padrão que são
necessários para a configuração do dispositivo, mas não são específicos para nenhum app, como pressHome
e scroll
. A classe auxiliar padrão é definida em AbstractAutoStandardAppHelper.java
.
As classes auxiliares de utilitário são usadas pelo framework. Por
exemplo, AutoJsonUtility.java
é uma
classe de utilitário que carrega o arquivo de configuração JSON do dispositivo e atualiza
as configurações do framework no tempo de execução.
O módulo de implementação do assistente do app é o núcleo do framework
da Spectatio. Ele contém a implementação das funções auxiliares definidas na
interface auxiliar do app, que são necessárias para testar apps em um
dispositivo automotivo. Cada app tem a própria implementação, como SettingHelperImpl
e
DialHelperImpl
,
usada pelos
testes do Automotive para testar os apps. Para mais informações e uma lista de
implementações, consulte as funções de implementação auxiliar de apps
no AOSP.
Os testes automotivos
usam as funções de implementação do assistente do app para testar várias operações
relacionadas a ele. Use a classe HelperAccessor
para ter acesso às funções de implementação do assistente do app.
O código a seguir mostra a configuração, a limpeza e a execução de um exemplo de teste automotivo.
@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());
}
}
Personalização
O framework Spectatio é independente da interface do dispositivo, portanto, é escalonável para
testar dispositivos com interfaces e hardwares variados. Para alcançar essa escalonabilidade,
o Spectatio usa as configurações de dispositivo padrão com base no dispositivo de referência. Para
oferecer suporte a configurações de dispositivo não padrão, o framework usa um arquivo de configuração
JSON no momento de execução para definir as mudanças de interface desejadas para o dispositivo. Um
arquivo de configuração JSON é compatível com elementos da interface, como TEXT
, DESCRIPTION
e
RESOURCE_ID
, e as configurações de path
. Além disso, ele precisa conter apenas as informações
sobre as mudanças na interface do DUT. Os outros elementos da interface usam os valores de
configuração padrão fornecidos no framework.
Configurações padrão do dispositivo
O exemplo de arquivo de configuração JSON abaixo mostra as configurações de dispositivo disponíveis e os valores padrão delas.
Clique aqui para exibir um exemplo de arquivo de configuração 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" } } } }
Configurações alternativas de dispositivos
O exemplo de código a seguir mostra um exemplo do arquivo de configuração JSON em que as configurações padrão são substituídas pelas configurações no DUT. Neste exemplo:
As configurações de Internet são nomeadas como Rede e Internet em dispositivos de referência e Conectividade no DUT.
As configurações de data e hora estão disponíveis em Configurações > Data e hora para dispositivos de referência e em Configurações > Sistema > Data e hora para o 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"
},
....
}
Quando o arquivo de configuração JSON estiver pronto, ele será fornecido no ambiente de execução, conforme mostrado no bloco de código a seguir:
# Push The JSON configuration file to the device
adb -s DEVICE-SERIAL push PATH-OF-JSON-FILE /data/local/tmp/runtimeSpectatioConfig.json
Nesse comando:
DEVICE-SERIAL: ID do serial do DUT. Esse parâmetro não será obrigatório se apenas um dispositivo estiver conectado ao host.
PATH-TO-JSON-FILE: caminho do arquivo JSON na máquina host.
Formato de configuração
Há cinco objetos de nível superior na configuração, com as seguintes chaves e valores:
Objeto | Descrição |
---|---|
PACKAGES |
Um objeto que descreve o pacote principal de vários apps, que são usados para determinar quando esse app está em primeiro plano. |
ACTIONS |
Um objeto que indica tipos e parâmetros de várias ações. Por exemplo, se é melhor usar botões ou um gesto para rolar. |
COMMANDS |
Um objeto que especifica comandos que executam várias ações. |
UI_ELEMENTS |
Um objeto usado para construir "BySelectors" do UI Automator que selecionam elementos da interface (descritos em detalhes abaixo). |
WORKFLOWS |
Sequências de ações que realizam tarefas de alto nível (descritas em detalhes abaixo). |
Elementos da interface
Cada elemento da interface tem um TYPE
que especifica o que o UI Automator vai procurar para
identificar o elemento (como ID do recurso, texto e descrição) e
os valores de configuração associados a esse tipo. Em geral, sempre que um auxiliar
identifica um elemento na tela usando essa configuração, ele recebe exatamente
um elemento. Se vários elementos corresponderem à configuração, um deles será
usado no teste. Portanto, a configuração precisa ser escrita
de forma específica para que se restrinja a um elemento no contexto relevante.
TEXT
Esse é o tipo de elemento de interface mais simples. O elemento da interface é identificado pelo texto e requer uma correspondência exata.
"CALL_HISTORY_MENU": {
"TYPE": "TEXT",
"VALUE": "Recents"
}
TEXT_CONTAINS
Igual a TEXT
, exceto que o VALUE
especificado só precisa aparecer em algum lugar do
texto do elemento a ser correspondido.
"PRIVACY_CALENDAR": {
"TYPE": "TEXT_CONTAINS",
"VALUE": "Calendar"
}
DESCRIÇÃO
Identifique o elemento pelo atributo de descrição do conteúdo, exigindo uma correspondência exata.
"APP_GRID_SCROLL_BACKWARD_BUTTON": {
"TYPE": "DESCRIPTION",
"VALUE": "Scroll up"
}
RESOURCE_ID
Identifique o elemento pelo ID de recurso e, se quiser, verifique também o componente
do pacote desse ID. A chave PACKAGE
é opcional. Se for omitida, qualquer pacote
será correspondente, e apenas a parte do ID após :id/
será considerada.
"APP_LIST_SCROLL_ELEMENT": {
"TYPE": "RESOURCE_ID",
"VALUE": "apps_grid",
"PACKAGE": "com.android.car.carlauncher"
}
CLICÁVEL, ROLÁVEL
Identifique o elemento com base no fato de ele ser (ou não) clicável ou rolável.
Esses são tipos de elementos muito amplos e geralmente devem ser usados apenas em um
MULTIPLE
para ajudar a restringir outro tipo de elemento. A chave FLAG
é opcional
e o padrão é true
.
"SAMPLE_ELEMENT": {
"TYPE": "CLICKABLE",
"FLAG": false
}
CLASSE
Identifique o elemento com base na classe dele.
"SECURITY_SETTINGS_ENTER_PASSWORD": {
"TYPE": "CLASS",
"VALUE": "android.widget.EditText"
}
HAS_ANCESTOR
Identifique o elemento procurando a hierarquia do widget nos ancestrais dele. A
chave ANCESTOR
contém um objeto que identifica o ancestral. A chave DEPTH
especifica até onde a hierarquia precisa ser analisada. DEPTH
é opcional e tem um
valor padrão de 1
.
"SAMPLE_ELEMENT": {
"TYPE": "HAS_ANCESTOR",
"DEPTH": 2,
"ANCESTOR": {
"TYPE": "CLASS",
"VALUE": "android.view.ViewGroup"
}
}
HAS_DESCENDANT
Identifique o elemento procurando pelos filhos na hierarquia. A
chave DESCENDANT
contém um objeto que especifica o filho a ser procurado. A
chave DEPTH
especifica o nível de detalhamento na hierarquia. DEPTH
é opcional e
tem um valor padrão de 1
.
"SAMPLE_ELEMENT": {
"TYPE": "HAS_DESCENDANT",
"DEPTH": 2,
"DESCENDANT": {
"TYPE": "CLASS",
"VALUE": "android.view.ViewGroup"
}
}
VÁRIAS
Identifique o elemento com base em várias condições simultâneas, que precisam ser atendidas.
"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"
}
}
]
}
Neste exemplo, a configuração identifica um RelativeLayout
que tem um
descendente na profundidade 2
, que tem o texto Permission manager
.
Workflows
Um fluxo de trabalho representa uma sequência de ações usadas para realizar uma tarefa específica, que pode diferir o suficiente de um tipo de dispositivo para outro e é mais flexível para representar na configuração do que no 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 fluxo de trabalho é um par de chave-valor, em que a chave é o nome do fluxo de trabalho e o valor é uma matriz de ações a serem executadas. Cada ação tem um NAME
, um TYPE
,
(geralmente) um CONFIG
e (às vezes) um SWIPE_CONFIG
ou SCROLL_CONFIG
. Para
a maioria dos TYPEs, o CONFIG
é um objeto com uma chave UI_ELEMENT
cujo valor tem
a mesma forma que uma entrada de elemento da interface (consulte acima). Esses TIPOS são:
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 |
Para os outros TYPEs, os detalhes de configuração são:
Objeto | Descrição |
---|---|
COMMAND |
Um objeto com um valor TEXT que contém o comando a ser executado. |
HAS_PACKAGE_IN_FOREGROUND |
Um objeto com um valor TEXT que contém o pacote. |
SWIPE |
Omita o CONFIG key para uma ação SWIPE . Ele
usa apenas SWIPE_CONFIG |
WAIT_MS |
Um objeto com um valor TEXT contendo o número de
milissegundos a serem aguardados. |
As ações relacionadas a rolagem e deslize exigem configuração adicional, da seguinte maneira:
SCROLL_CONFIG
Objeto | Descrição |
---|---|
SCROLL_ACTION |
USE_GESTURE ou USE_BUTTON |
SCROLL_DIRECTION |
HORIZONTAL ou VERTICAL |
SCROLL_ELEMENT |
Um objeto que indica o contêiner a ser rolado, usando a mesma forma de uma configuração de elemento da IU (veja acima). |
SCROLL_FORWARD , SCROLL_BACKWARD |
Os botões de rolagem para frente e para trás (obrigatório quando
SCROLL_ACTION é USE_BUTTON ). |
SCROLL_MARGIN |
Se SCROLL_ACTION for USE_GESTURE , a distância
da borda do contêiner para iniciar e interromper o arrasto que será usado
para rolar (Opcional,padrão = 10). |
SCROLL_WAIT_TIME |
Se SCROLL_ACTION for USE_GESTURE , o tempo em
milissegundos para aguardar entre gestos de rolagem ao procurar um objeto para
clicar.
(Opcional, padrão = 1). |
SWIPE_CONFIG
Objeto | Descrição |
---|---|
SWIPE_DIRECTION |
TOP_TO_BOTTOM , BOTTOM_TO_TOP ,
LEFT_TO_RIGHT ou RIGHT_TO_LEFT |
SWIPE_FRACTION |
Uma das seguintes opções:
|
NUMBER_OF_STEPS |
O número de etapas a serem usadas para realizar o deslizar. Consulte
segmentSteps .
|
Criar e executar
O framework Spectatio é criado automaticamente como parte do APK de teste. Para criar o APK de teste, o código-base do AOSP precisa residir na estação de trabalho local. Depois que o APK de teste é criado, o usuário precisa instalar o APK no dispositivo e executar o teste.
O exemplo de código abaixo mostra a criação, instalação e execução de um APK de teste.
# 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
Nesses comandos:
TEST-APK-NAME: o nome do app a ser testado. Por exemplo, defina TEST-APK-NAME como
AndroidAutomotiveSettingsTests
para testar as configurações de Wi-Fi conforme especificado no arquivoAndroid.bp
. O nome do APK pode ser encontrado no arquivoAndroid.bp
correspondente para o teste automotivo.DEVICE-SERIAL: o ID do lote do DUT. Esse parâmetro não é necessário se apenas um dispositivo estiver conectado ao host.
config-file-path
: parâmetro opcional necessário apenas para fornecer configurações de IU do dispositivo não padrão, conforme especificado no arquivo de configuração JSON. Se não forem fornecidos, o framework vai usar valores padrão para executar os testes.PATH-FOR-BUILT-TEST-APK: o caminho em que o APK de teste é criado quando o comando
make
é executado.TEST-PACKAGE: o nome do pacote de teste.
TEST-CLASSNAME: o nome da classe de teste. Por exemplo, para o teste Configurações de Wi-Fi, o pacote de teste é
android.platform.tests
e o nome da classe de teste éWifiSettingTest
.
Biblioteca de snippets automotivos
A biblioteca de snippets automotivos é um conjunto de bibliotecas do Android Test para o Android Open Source Project (AOSP), projetado para interagir com apps e serviços automotivos. Ele usa o Spectatio com um mecanismo conveniente para executar chamadas de procedimento remoto (RPCs) de uma máquina host (de teste) para um dispositivo Android.
Primeiros passos
Antes de começar, leia estas seções.
Pré-requisitos
- Python 3.x instalado na máquina host.
- Configuração do ambiente AOSP com as ferramentas de build necessárias.
- Um dispositivo automotivo Android (emulador ou dispositivo físico) com acesso ao adb.
Compilação
Para compilar os vários snippets fornecidos pela biblioteca de snippets automotivos, use o arquivo android.bp
fornecido. Siga os comandos na seção anterior
para compilar o APK.
Implantação
Depois de compilar as bibliotecas de snippets, implante os APKs resultantes no
dispositivo de destino usando o comando adb install
mencionado na seção
anterior.
Executar testes
As bibliotecas de snippet expõem vários métodos RPC para interagir com o sistema
automotivo. Esses métodos podem ser invocados pelo framework Mobly na máquina
host. Supondo que você tenha configurado o ambiente de teste do Mobly, use o script
snippet_shell.py
para abrir um shell interativo do Python, em que é possível
invocar manualmente métodos RPC no dispositivo. Exemplo de invocação:
python3 snippet_shell.py com.google.android.mobly.snippet.bundled -s <serial>
Substitua <serial>
pelo número de série do dispositivo, que pode ser encontrado com
dispositivos adb se vários dispositivos estiverem conectados.
Bibliotecas incluídas
A biblioteca de snippets automotivo inclui as seguintes bibliotecas e ajudantes de snippet:
AutomotiveSnippet: fornece APIs relacionadas a operações do veículo, como discagem, controle de volume, teclas físicas do veículo e interação com o centro de mídia.
PhoneSnippet: fornece APIs relacionadas à telefonia, incluindo processamento de chamadas, navegação de contatos e operações de SMS.
O snippet de automóveis e o PhoneSnippet compartilham uma lógica comum.
Especificamente, você pode invadir chamadas RCP relacionadas ao Bluetooth para parear um dispositivo automotivo
e um smartphone. Este bt_discovery_test
mostra como.
- TEST-CLASSNAME: o nome da classe de teste. Por exemplo, no teste
Configurações de Wi-Fi,
o pacote de teste é
android.platform.tests
e o nome da classe de teste éWifiSettingTest
.