Se você não conhece o Bazel, comece com o tutorial Como criar apps Android com o Bazel.

Figura 1. Execução de testes de instrumentação do Android em paralelo.
android_instrumentation_test
permite que os desenvolvedores testem os apps em emuladores e dispositivos Android.
Ele usa APIs reais do framework Android e a biblioteca de testes do Android.
Para garantir a hermeticidade e a reprodutibilidade, o Bazel cria e inicia emuladores Android em um ambiente de sandbox, garantindo que os testes sejam sempre executados em um estado limpo. Cada teste recebe uma instância de emulador isolada, permitindo que os testes sejam executados em paralelo sem passar estados entre eles.
Para mais informações sobre testes de instrumentação do Android, consulte a documentação para desenvolvedores do Android.
Registre problemas no Issue Tracker do GitHub (em inglês).
Como funciona
Quando você executa bazel test em um destino android_instrumentation_test pela
primeira vez, o Bazel realiza as seguintes etapas:
- Cria o APK de teste, o APK em teste e as dependências transitivas deles.
- Cria, inicializa e armazena em cache estados de emulador limpos.
- Inicia o emulador.
- Instala os APKs.
- Executa testes usando o Android Test Orchestrator.
- Desliga o emulador.
- Informa os resultados.
Em execuções de teste subsequentes, o Bazel inicializa o emulador no estado limpo e armazenado em cache criado na etapa 2. Portanto, não há estados restantes de execuções anteriores. O estado do emulador de armazenamento em cache também acelera as execuções de teste.
Pré-requisitos
Confira se o ambiente atende aos seguintes pré-requisitos:
Linux. Testado no Ubuntu 16.04 e 18.04.
Bazel 0.12.0 ou mais recente. Verifique a versão executando
bazel info release.
bazel info releaseIsso resulta em uma saída semelhante a esta:
release 4.1.0
- KVM. O Bazel exige que os emuladores tenham aceleração de hardware com KVM no Linux. Siga estas instruções de instalação para o Ubuntu.
Para verificar se o KVM tem a configuração correta, execute:
apt-get install cpu-checker && kvm-okSe a seguinte mensagem for impressa, você terá a configuração correta:
INFO: /dev/kvm exists
KVM acceleration can be used
- Xvfb. Para executar testes sem comando (por exemplo, em servidores de CI), o Bazel exige o framebuffer virtual X.
Para instalar, execute:
apt-get install xvfbVerifique se o Xvfb está instalado corretamente e se está instalado em /usr/bin/Xvfb
executando:
which XvfbA saída é esta:
/usr/bin/Xvfb
- Bibliotecas de 32 bits. Alguns dos binários usados pela infraestrutura de teste são de 32 bits. Portanto, em máquinas de 64 bits, verifique se os binários de 32 bits podem ser executados. Para o Ubuntu, instale estas bibliotecas de 32 bits:
sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 lib32z1 libbz2-1.0:i386Primeiros passos
Confira a seguir 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 é convertido 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. Oandroid_binarydestino selecionado precisa especificar um atributoinstrumentsque aponta para outroandroid_binary, que é o app em teste.target_device: um destinoandroid_device. Esse destino descreve as especificações do emulador Android que o Bazel usa para criar, iniciar e executar os testes. Consulte a seção sobre como escolher um dispositivo Android para mais informações.
O AndroidManifest.xml do app de teste precisa incluir uma <instrumentation>
tag.
Essa tag precisa especificar os atributos do pacote do app de destino e
o nome de classe totalmente qualificado do executor de testes de instrumentação,
androidx.test.runner.AndroidJUnitRunner.
Confira a seguir 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 WORKSPACE
Para usar essa regra, seu projeto precisa depender destes repositórios externos:
@androidsdk: o SDK do Android. Faça o download pelo Android Studio.@android_test_support: hospeda o executor de testes, o inicializador do emulador e os destinosandroid_device. Confira a versão mais recente neste link.
Ative essas dependências adicionando as seguintes linhas ao seu 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 do Maven de repositórios, como Google
Maven ou Maven Central,
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 do Maven.
Como escolher um destino android_device
android_instrumentation_test.target_device especifica em qual dispositivo Android
os testes serão executados. Esses android_device destinos são definidos em
@android_test_support.
Por exemplo, você pode consultar as fontes de um destino específico executando:
bazel query --output=build @android_test_support//tools/android/emulated_devices/generic_phone:android_23_x86Isso resulta em uma saída semelhante a esta:
# .../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 de destino do dispositivo usam este modelo:
@android_test_support//tools/android/emulated_devices/device_type:system_api_level_x86_qemu2
Para iniciar um android_device, a system_image do nível da API selecionado é necessária. Para fazer o download da imagem do sistema, use
tools/bin/sdkmanager do SDK do Android. Por exemplo, para fazer o download da imagem do sistema para
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/...:*))'No momento, o Bazel oferece suporte apenas a emuladores baseados em x86. Para melhorar o desempenho, use
QEMU2 android_device destinos em vez de QEMU.
Como executar testes
Para executar testes, adicione estas linhas ao arquivo
project root:/.bazelrc do projeto.
# 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=guibazel test //my/test:target --config=headlessbazel test //my/test:target --config=local_device
Use apenas uma configuração ou os testes vão falhar.
Teste sem comando
Com Xvfb, é possível testar com emuladores sem a interface gráfica, também conhecida como teste sem comando. 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=falseTeste de GUI
Se a variável de ambiente $DISPLAY estiver definida, será possível ativar a
interface gráfica do emulador enquanto o teste estiver em execução. Para fazer isso, transmita
esses argumentos de teste para o Bazel:
bazel test //my/test:target --test_arg=--enable_display=true --test_env=DISPLAYComo testar com um emulador ou dispositivo local
O Bazel também oferece suporte a testes diretamente em um emulador iniciado localmente ou em um dispositivo conectado. Transmita as flags
--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 flag
--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 de projetos canônicos, consulte os exemplos de testes do Android para projetos que usam o Espresso e o UIAutomator.
Configuração do Espresso
Se você escrever testes de interface com o Espresso
(androidx.test.espresso), poderá usar os snippets a seguir para configurar o
espaço de trabalho do Bazel com a lista de artefatos do Espresso usados com frequência e as
dependências deles:
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 uma biblioteca compartilhada //:test_deps no arquivo project root/BUILD.bazel file:
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 do teste, adicione a //: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 com falha ou
--test_output=all para imprimir toda a saída de teste. Se você estiver procurando um
registro de teste individual, acesse
$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/BasicSampleInstrumentationTestIsso 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/
diretório com o nome emulator_xxxxx.log, em que xxxxx é uma
sequência de caracteres gerada aleatoriamente.
Use este comando para encontrar o registro do emulador mais recente:
ls -1t /tmp/emulator_*.log | head -n 1Como testar em vários níveis de API
Se você quiser testar em vários níveis de API, use uma compreensão de lista para criar destinos de teste para cada nível de API. Por 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 do servidor adb bifurcados não são encerrados após os testes
- Embora a criação de APKs funcione em todas as plataformas (Linux, macOS, Windows), os testes só funcionam no Linux.
- Mesmo com
--config=local_adb, os usuários ainda precisam especificarandroid_instrumentation_test.target_device. - Se você estiver usando um dispositivo ou emulador local, o Bazel não vai desinstalar os APKs após 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