Se você não conhece o Bazel, comece pelo laboratório Como criar para o Android com Tutorial do Bazel.
Figura 1. Execução de testes paralelos de instrumentação do Android.
android_instrumentation_test
permite que os desenvolvedores testem apps em emuladores e dispositivos Android.
Ele usa APIs de framework reais do Android e a biblioteca Android Test.
Para hermética e reprodutibilidade, o Bazel cria e inicia o Android emuladores em um sandbox, garantindo que os testes sejam sempre executados em um estado limpo. Cada teste recebe uma instância de emulador isolada, permitindo que testes sejam executados em paralelo sem transmitir estados entre elas.
Para mais informações sobre os testes de instrumentação no Android, consulte a página do desenvolvedor Documentação.
Informe os problemas no Issue Tracker do GitHub.
Como funciona
Quando você executa bazel test
em um destino android_instrumentation_test
para o
pela primeira vez, o Bazel executa as seguintes etapas:
- Cria o APK de teste, o APK em teste e as respectivas dependências transitivas
- Cria, inicializa e armazena em cache estados limpos do emulador
- Inicia o emulador
- Instala os APKs
- Executa testes usando o Android Test Orchestrator.
- Desliga o emulador
- Informa os resultados
Nas execuções de teste subsequentes, o Bazel inicializa o emulador do estado limpo e armazenado em cache. criado na etapa 2 para que não haja estados restantes de execuções anteriores. Armazenamento em cache do emulador também acelera as execuções de teste.
Pré-requisitos
Verifique se o ambiente atende aos seguintes pré-requisitos:
Linux: Testado no Ubuntu 16.04 e 18.04.
Bazel 0.12.0 ou mais recente. Execute
bazel info release
para verificar a versão.
bazel info release
O resultado será semelhante a este:
release 4.1.0
- KVM (em inglês). O Bazel exige que os emuladores tenham recursos de hardware aceleração com a KVM no Linux. Você pode seguir estas instruções de instalação para Ubuntu.
Para verificar se a KVM tem a configuração correta, execute:
apt-get install cpu-checker && kvm-ok
Se aparecer a mensagem a seguir, você tem a configuração correta:
INFO: /dev/kvm exists
KVM acceleration can be used
- Xvfb (link em inglês). Para executar testes sem comando (por exemplo, em servidores de CI), o Bazel exige o framebuffer virtual X.
Para instalá-lo, execute:
apt-get install xvfb
Verifique se o app Xvfb
está instalado corretamente e em /usr/bin/Xvfb
executando:
which Xvfb
A saída é esta:
/usr/bin/Xvfb
- Bibliotecas de 32 bits. Alguns dos binários usados pela infraestrutura de testes são 32 bits, portanto, em máquinas de 64 bits, garante que os binários de 32 bits possam ser executados. Para Ubuntu, instale estas bibliotecas de 32 bits:
sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 lib32z1 libbz2-1.0:i386
Primeiros passos
Este é um gráfico de dependência de destino típico de um android_instrumentation_test
:
Figura 2. Gráfico de dependência de destino de um android_instrumentation_test
.
Arquivo BUILD
O gráfico é traduzido em um arquivo BUILD
como este:
android_instrumentation_test(
name = "my_test",
test_app = ":my_test_app",
target_device = "@android_test_support//tools/android/emulated_devices/generic_phone:android_23_x86",
)
# Test app and library
android_binary(
name = "my_test_app",
instruments = ":my_app",
manifest = "AndroidTestManifest.xml",
deps = [":my_test_lib"],
# ...
)
android_library(
name = "my_test_lib",
srcs = glob(["javatest/**/*.java"]),
deps = [
":my_app_lib",
"@maven//:androidx_test_core",
"@maven//:androidx_test_runner",
"@maven//:androidx_test_espresso_espresso_core",
],
# ...
)
# Target app and library under test
android_binary(
name = "my_app",
manifest = "AndroidManifest.xml",
deps = [":my_app_lib"],
# ...
)
android_library(
name = "my_app_lib",
srcs = glob(["java/**/*.java"]),
deps = [
"@maven//:androidx_appcompat_appcompat",
"@maven//:androidx_annotation_annotation",
]
# ...
)
Os principais atributos da regra android_instrumentation_test
são:
test_app
: um destinoandroid_binary
. Esse destino contém código de teste e dependências como Espresso e UIAutomator. O(a)android_binary
selecionado(a) destino é necessário para especificar um atributoinstruments
que aponta para outroandroid_binary
, que é o app em teste.target_device
: um destinoandroid_device
. Esse objetivo descreve especificações do Android Emulator que o Bazel usa para criar, iniciar e para executar os testes. Consulte a seção sobre como escolher um dispositivo dispositivo para mais informações.
O AndroidManifest.xml
do app de teste precisa incluir um <instrumentation>
.
tag.
Essa tag precisa especificar os atributos para o pacote do app de destino e
o nome da classe totalmente qualificado do executor de testes de instrumentação,
androidx.test.runner.AndroidJUnitRunner
Confira um exemplo de AndroidTestManifest.xml
para o app de teste:
<?xml version="1.0" encoding="UTF-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.android.app.test"
android:versionCode="1"
android:versionName="1.0">
<instrumentation
android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.example.android.app" />
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="27" />
<application >
<!-- ... -->
</application>
</manifest>
dependências do ESPAÇO DE TRABALHO
Para usar essa regra, seu projeto precisa depender destes recursos repositórios:
@androidsdk
: o SDK do Android. Faça o download pelo Android Studio.@android_test_support
: hospeda o executor de testes, o inicializador do emulador eandroid_device
metas. Encontre a versão mais recente aqui.
Para ativar essas dependências, adicione as seguintes linhas ao arquivo WORKSPACE
arquivo:
# Android SDK
android_sdk_repository(
name = "androidsdk",
path = "/path/to/sdk", # or set ANDROID_HOME
)
# Android Test Support
ATS_COMMIT = "$COMMIT_HASH"
http_archive(
name = "android_test_support",
strip_prefix = "android-test-%s" % ATS_COMMIT,
urls = ["https://github.com/android/android-test/archive/%s.tar.gz" % ATS_COMMIT],
)
load("@android_test_support//:repo.bzl", "android_test_repositories")
android_test_repositories()
Dependências do Maven
Para gerenciar dependências em artefatos Maven de repositórios, como os do Google
Maven ou Maven Central (em inglês),
use um resolvedor do Maven, como
rules_jvm_external
O restante desta página mostra como usar rules_jvm_external
para
resolver e buscar dependências de repositórios Maven.
Como escolher um destino de android_device
android_instrumentation_test.target_device
especifica qual dispositivo Android
para executar os testes. Essas metas de android_device
são definidas em
@android_test_support
.
Por exemplo, para consultar as origens de um destino específico, execute:
bazel query --output=build @android_test_support//tools/android/emulated_devices/generic_phone:android_23_x86
O que resulta em uma saída semelhante a:
# .../external/android_test_support/tools/android/emulated_devices/generic_phone/BUILD:43:1
android_device(
name = "android_23_x86",
visibility = ["//visibility:public"],
tags = ["requires-kvm"],
generator_name = "generic_phone",
generator_function = "make_device",
generator_location = "tools/android/emulated_devices/generic_phone/BUILD:43",
vertical_resolution = 800,
horizontal_resolution = 480,
ram = 2048,
screen_density = 240,
cache = 32,
vm_heap = 256,
system_image = "@android_test_support//tools/android/emulated_devices/generic_phone:android_23_x86_images",
default_properties = "@android_test_support//tools/android/emulated_devices/generic_phone:_android_23_x86_props",
)
Os nomes dos destinos de dispositivo usam este modelo:
@android_test_support//tools/android/emulated_devices/device_type:system_api_level_x86_qemu2
Para iniciar um android_device
, o system_image
da API selecionada
nível é obrigatório. Para fazer o download da imagem do sistema, use o SDK do Android
tools/bin/sdkmanager
: Por exemplo, para baixar a imagem do sistema do
generic_phone:android_23_x86
, execute $sdk/tools/bin/sdkmanager
"system-images;android-23;default;x86"
.
Para conferir a lista completa de destinos android_device
compatíveis em
@android_test_support
, execute o seguinte comando:
bazel query 'filter("x86_qemu2$", kind(android_device, @android_test_support//tools/android/emulated_devices/...:*))'
Atualmente, o Bazel oferece suporte apenas a emuladores baseados em x86. Para um melhor desempenho, use
QEMU2
destinos android_device
em vez de QEMU
.
Como executar testes
Para executar testes, adicione estas linhas ao
project root:/.bazelrc
.
# Configurations for testing with Bazel
# Select a configuration by running
# `bazel test //my:target --config={headless, gui, local_device}`
# Headless instrumentation tests (No GUI)
test:headless --test_arg=--enable_display=false
# Graphical instrumentation tests. Ensure that $DISPLAY is set.
test:gui --test_env=DISPLAY
test:gui --test_arg=--enable_display=true
# Testing with a local emulator or device. Ensure that `adb devices` lists the
# device.
# Run tests serially.
test:local_device --test_strategy=exclusive
# Use the local device broker type, as opposed to WRAPPED_EMULATOR.
test:local_device --test_arg=--device_broker_type=LOCAL_ADB_SERVER
# Uncomment and set $device_id if there is more than one connected device.
# test:local_device --test_arg=--device_serial_number=$device_id
Em seguida, use uma das configurações para executar testes:
bazel test //my/test:target --config=gui
bazel test //my/test:target --config=headless
bazel test //my/test:target --config=local_device
Use apenas uma configuração ou os testes falharão.
Teste headless
Com Xvfb
, é possível testar com emuladores sem a interface
também conhecido como teste headless. Para desativar a interface gráfica
ao executar testes, transmita o argumento de teste --enable_display=false
para o Bazel:
bazel test //my/test:target --test_arg=--enable_display=false
Teste de GUI
Se a variável de ambiente $DISPLAY
estiver definida, será possível ativar a
interface gráfica do emulador enquanto o teste está em execução. Para fazer isso, transmita
estes argumentos de teste ao Bazel:
bazel test //my/test:target --test_arg=--enable_display=true --test_env=DISPLAY
Como testar com um emulador ou dispositivo local
O Bazel também oferece suporte a testes diretamente em um emulador iniciado localmente ou conectado
dispositivo. Passar as sinalizações
--test_strategy=exclusive
e
--test_arg=--device_broker_type=LOCAL_ADB_SERVER
para ativar o modo de teste local.
Se houver mais de um dispositivo conectado, transmita a sinalização
--test_arg=--device_serial_number=$device_id
em que $device_id
é o ID de
o dispositivo/emulador listado em adb devices
.
Projetos de amostra
Se você estiver procurando exemplos canônicos de projetos, consulte a página de testes para Android amostras para projetos que usam o Espresso e o UIAutomator.
Configuração do Espresso
Se você programa testes de interface com o Espresso
(androidx.test.espresso
), use os snippets a seguir para configurar
Espaço de trabalho do Bazel com a lista dos artefatos mais usados do Espresso e os respectivos
dependências:
androidx.test.espresso:espresso-core
androidx.test:rules
androidx.test:runner
javax.inject:javax.inject
org.hamcrest:java-hamcrest
junit:junit
Uma maneira de organizar essas dependências é criar um arquivo compartilhado pelo //:test_deps
no arquivo project root/BUILD.bazel
:
java_library(
name = "test_deps",
visibility = ["//visibility:public"],
exports = [
"@maven//:androidx_test_espresso_espresso_core",
"@maven//:androidx_test_rules",
"@maven//:androidx_test_runner",
"@maven//:javax_inject_javax_inject"
"@maven//:org_hamcrest_java_hamcrest",
"@maven//:junit_junit",
],
)
Em seguida, adicione as dependências necessárias em project root/WORKSPACE
:
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
RULES_JVM_EXTERNAL_TAG = "2.8"
RULES_JVM_EXTERNAL_SHA = "79c9850690d7614ecdb72d68394f994fef7534b292c4867ce5e7dec0aa7bdfad"
http_archive(
name = "rules_jvm_external",
strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG,
sha256 = RULES_JVM_EXTERNAL_SHA,
url = "https://github.com/bazelbuild/rules_jvm_external/archive/%s.zip" % RULES_JVM_EXTERNAL_TAG,
)
load("@rules_jvm_external//:defs.bzl", "maven_install")
maven_install(
artifacts = [
"junit:junit:4.12",
"javax.inject:javax.inject:1",
"org.hamcrest:java-hamcrest:2.0.0.0"
"androidx.test.espresso:espresso-core:3.1.1",
"androidx.test:rules:aar:1.1.1",
"androidx.test:runner:aar:1.1.1",
],
repositories = [
"https://maven.google.com",
"https://repo1.maven.org/maven2",
],
)
Por fim, no destino android_binary
de teste, adicione o //:test_deps
dependência:
android_binary(
name = "my_test_app",
instruments = "//path/to:app",
deps = [
"//:test_deps",
# ...
],
# ...
)
Dicas
Como ler registros de teste
Use --test_output=errors
para imprimir registros de testes reprovados ou
--test_output=all
para mostrar toda a saída de teste. Se você está procurando
registro de teste individual, vá para
$PROJECT_ROOT/bazel-testlogs/path/to/InstrumentationTestTargetName
:
Por exemplo, os registros de teste do projeto canônico BasicSample
estão em
bazel-testlogs/ui/espresso/BasicSample/BasicSampleInstrumentationTest
, execute:
tree bazel-testlogs/ui/espresso/BasicSample/BasicSampleInstrumentationTest
Isso resulta na seguinte saída:
$ tree bazel-testlogs/ui/espresso/BasicSample/BasicSampleInstrumentationTest
.
├── adb.409923.log
├── broker_logs
│ ├── aapt_binary.10.ok.txt
│ ├── aapt_binary.11.ok.txt
│ ├── adb.12.ok.txt
│ ├── adb.13.ok.txt
│ ├── adb.14.ok.txt
│ ├── adb.15.fail.txt
│ ├── adb.16.ok.txt
│ ├── adb.17.fail.txt
│ ├── adb.18.ok.txt
│ ├── adb.19.fail.txt
│ ├── adb.20.ok.txt
│ ├── adb.21.ok.txt
│ ├── adb.22.ok.txt
│ ├── adb.23.ok.txt
│ ├── adb.24.fail.txt
│ ├── adb.25.ok.txt
│ ├── adb.26.fail.txt
│ ├── adb.27.ok.txt
│ ├── adb.28.fail.txt
│ ├── adb.29.ok.txt
│ ├── adb.2.ok.txt
│ ├── adb.30.ok.txt
│ ├── adb.3.ok.txt
│ ├── adb.4.ok.txt
│ ├── adb.5.ok.txt
│ ├── adb.6.ok.txt
│ ├── adb.7.ok.txt
│ ├── adb.8.ok.txt
│ ├── adb.9.ok.txt
│ ├── android_23_x86.1.ok.txt
│ └── exec-1
│ ├── adb-2.txt
│ ├── emulator-2.txt
│ └── mksdcard-1.txt
├── device_logcat
│ └── logcat1635880625641751077.txt
├── emulator_itCqtc.log
├── outputs.zip
├── pipe.log.txt
├── telnet_pipe.log.txt
└── tmpuRh4cy
├── watchdog.err
└── watchdog.out
4 directories, 41 files
Como ler registros do emulador
Os registros do emulador para destinos android_device
são armazenados no /tmp/
com o nome emulator_xxxxx.log
, em que xxxxx
é um
uma sequência de caracteres gerada aleatoriamente.
Use este comando para encontrar o registro mais recente do emulador:
ls -1t /tmp/emulator_*.log | head -n 1
Como testar em vários níveis de API
Se quiser testar em vários níveis de API, você pode usar uma lista compreensão para criar destinos de teste para cada nível da API. Exemplo:
API_LEVELS = [
"19",
"20",
"21",
"22",
]
[android_instrumentation_test(
name = "my_test_%s" % API_LEVEL,
test_app = ":my_test_app",
target_device = "@android_test_support//tools/android/emulated_devices/generic_phone:android_%s_x86_qemu2" % API_LEVEL,
) for API_LEVEL in API_LEVELS]
Problemas conhecidos
- Os processos bifurcados do servidor adb não são encerrados após testes
- Embora a criação de APKs funcione em todas as plataformas (Linux, macOS e Windows), os testes só funciona no Linux.
- Mesmo com
--config=local_adb
, os usuários ainda precisam especificarandroid_instrumentation_test.target_device
. - Se estiver usando um dispositivo ou emulador local, o Bazel não vai desinstalar os APKs depois o teste. Limpe os pacotes executando este comando:
adb shell pm list
packages com.example.android.testing | cut -d ':' -f 2 | tr -d '\r' | xargs
-L1 -t adb uninstall