Bazel'i kullanmaya yeni başladıysanız önce Bazel ile Android Oluşturma eğiticisini inceleyin.
Şekil 1. Paralel Android araç testleri yapılıyor.
android_instrumentation_test
, geliştiricilerin uygulamalarını Android emülatörlerinde ve cihazlarda test etmelerine olanak tanır.
Gerçek Android çerçevesi API'lerini ve Android Test Kitaplığı'nı kullanır.
Bazel, hermetiklik ve yeniden üretilebilirlik için Android emülatörlerini korumalı alanda oluşturup kullanıma sunarak testlerin her zaman temiz bir durumda çalışmasını sağlar. Her test, izole bir emülatör örneği alır. Böylece testler, aralarında durumlar geçirilmeden paralel olarak yürütülebilir.
Android araç testleri hakkında daha fazla bilgi için Android geliştirici belgelerine göz atın.
Lütfen sorunları GitHub sorun izleyiciye gönderin.
İşleyiş şekli
bazel test
öğesini android_instrumentation_test
hedefinde ilk kez çalıştırdığınızda Bazel aşağıdaki adımları gerçekleştirir:
- Test APK'sını, test edilen APK'yı ve bunların geçişli bağımlılıklarını oluşturur
- Temiz emülatör durumları oluşturur, başlatır ve önbelleğe alır
- Emülatörü başlatır
- APK'ları yükler
- Android Test Orchestrator'ı kullanarak testler çalıştırır.
- Emülatörü kapatır
- Sonuçları bildirir
Sonraki test çalıştırmalarında Bazel, emülatörü 2. adımda oluşturulan temiz, önbelleğe alınmış durumdan başlatır. Böylece, önceki çalıştırmalarda kalan durumlar olmaz. Emülatör durumunu önbelleğe almak, test çalıştırmalarını da hızlandırır.
Ön koşullar
Ortamınızın aşağıdaki ön koşulları karşıladığından emin olun:
Linux. Ubuntu 16.04 ve 18.04'te test edilmiştir.
Bazel 0.12.0 veya sonraki sürümler.
bazel info release
komutunu çalıştırarak sürümü doğrulayın.
bazel info release
Bu işlemden sonra şuna benzer bir çıkış elde edilir:
release 4.1.0
- KVM'ye gidin. Bazel, Linux'ta KVM ile emülatörlerin donanım hızlandırma kullanmasını gerektirir. Ubuntu için bu yükleme talimatlarını uygulayabilirsiniz.
KVM'nin doğru yapılandırmaya sahip olduğunu doğrulamak için aşağıdaki komutu çalıştırın:
apt-get install cpu-checker && kvm-ok
Aşağıdaki mesaj gösteriliyorsa yapılandırma doğrudur:
INFO: /dev/kvm exists
KVM acceleration can be used
- Xvfb olmalıdır. Bazel, gözetimsiz testler (örneğin CI sunucularında) çalıştırmak için X sanal çerçeve arabelleğine ihtiyaç duyar.
Yüklemek için şu komutu çalıştırın:
apt-get install xvfb
Şu komutu çalıştırarak Xvfb
öğesinin doğru şekilde yüklendiğini ve /usr/bin/Xvfb
adresine yüklendiğini doğrulayın:
which Xvfb
Çıkış şu şekildedir:
/usr/bin/Xvfb
- 32 Bit Kitaplıklar. Test altyapısı tarafından kullanılan ikili programlardan bazıları 32 bit olduğundan, 64 bit makinelerde 32 bit ikili programların çalıştırılabileceğinden emin olun. Ubuntu için şu 32 bit kitaplıkları yükleyin:
sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 lib32z1 libbz2-1.0:i386
Başlarken
Aşağıda android_instrumentation_test
için tipik bir hedef bağımlılık grafiği verilmiştir:
Şekil 2. android_instrumentation_test
hedef bağımlılık grafiği.
BUILD dosyası
Grafik şuna benzer bir BUILD
dosyasına dönüşür:
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",
]
# ...
)
android_instrumentation_test
kuralının ana özellikleri şunlardır:
test_app
:android_binary
hedefidir. Bu hedef, test kodunu ve Espresso ile UIAutomator gibi bağımlılıkları içerir. Seçilenandroid_binary
hedefi, test edilen uygulama olan başka birandroid_binary
öğesine işaret edeninstruments
özelliğini belirtmek için gereklidir.target_device
:android_device
hedefidir. Bu hedefte Bazel'in testleri oluşturmak, başlatmak ve çalıştırmak için kullandığı Android emülatörünün özellikleri açıklanmaktadır. Daha fazla bilgi için Android cihaz seçme bölümüne göz atın.
Test uygulamasının AndroidManifest.xml
öğesi <instrumentation>
etiketi içermelidir.
Bu etiket, hedef uygulamanın paketi ve araç test çalıştırıcısının tam nitelikli sınıf adını, androidx.test.runner.AndroidJUnitRunner
özelliklerini belirtmelidir.
Test uygulaması için aşağıda örnek bir AndroidTestManifest.xml
verilmiştir:
<?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>
WORKSPACE bağımlılıkları
Bu kuralı kullanmak için projenizin şu harici depolara bağlı olması gerekir:
@androidsdk
: Android SDK'sı. Bunu Android Studio'dan indirin.@android_test_support
: Test çalıştırıcısını, emülatör başlatıcıyı veandroid_device
hedeflerini barındırır. En son sürümü burada bulabilirsiniz.
Aşağıdaki satırları WORKSPACE
dosyanıza ekleyerek bu bağımlılıkları etkinleştirin:
# 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()
Maven bağımlılıkları
Google Maven veya Maven Central gibi depolardaki Maven yapılarına olan bağımlılıkları yönetmek için rules_jvm_external
gibi bir Maven çözümleyicisi kullanmanız gerekir.
Bu sayfanın geri kalanında, Maven depolarındaki bağımlılıkları çözümlemek ve getirmek için rules_jvm_external
hizmetinin nasıl kullanılacağı gösterilmektedir.
android_device hedefi seçme
android_instrumentation_test.target_device
, testlerin hangi Android cihazda çalıştırılacağını belirtir. Bu android_device
hedef @android_test_support
içinde tanımlanmıştır.
Örneğin, aşağıdaki komutu çalıştırarak belirli bir hedefe ilişkin kaynakları sorgulayabilirsiniz:
bazel query --output=build @android_test_support//tools/android/emulated_devices/generic_phone:android_23_x86
Bu durumda şuna benzer bir çıkış elde edilir:
# .../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",
)
Cihaz hedefi adları şu şablonu kullanır:
@android_test_support//tools/android/emulated_devices/device_type:system_api_level_x86_qemu2
Bir android_device
başlatmak için seçili API düzeyinin system_image
değeri gereklidir. Sistem görüntüsünü indirmek için Android SDK'sının tools/bin/sdkmanager
kullanın. Örneğin, generic_phone:android_23_x86
için sistem görüntüsünü indirmek üzere $sdk/tools/bin/sdkmanager
"system-images;android-23;default;x86"
komutunu çalıştırın.
@android_test_support
bölgesinde desteklenen android_device
hedeflerinin tam listesini görmek için aşağıdaki komutu çalıştırın:
bazel query 'filter("x86_qemu2$", kind(android_device, @android_test_support//tools/android/emulated_devices/...:*))'
Bazel şu anda yalnızca x86 tabanlı emülatörleri desteklemektedir. Daha iyi performans için QEMU
hedefleri yerine QEMU2
android_device
hedeflerini kullanın.
Testler yapılıyor
Testleri çalıştırmak için bu satırları projenizin project root:/.bazelrc
dosyasına ekleyin.
# 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
Ardından, testleri çalıştırmak için yapılandırmalardan birini kullanın:
bazel test //my/test:target --config=gui
bazel test //my/test:target --config=headless
bazel test //my/test:target --config=local_device
Yalnızca bir yapılandırma kullanın. Aksi takdirde testler başarısız olur.
Gözetimsiz test
Xvfb
sayesinde, gözetimsiz test olarak da bilinen, grafik arayüz olmadan emülatörlerle test yapılabilir. Testleri çalıştırırken grafik arayüzü devre dışı bırakmak için --enable_display=false
test bağımsız değişkenini Bazel'a iletin:
bazel test //my/test:target --test_arg=--enable_display=false
GUI testi
$DISPLAY
ortam değişkeni ayarlanmışsa test çalışırken emülatörün grafik arayüzü etkinleştirilebilir. Bunu yapmak için aşağıdaki test
argümanlarını Bazel'a iletin:
bazel test //my/test:target --test_arg=--enable_display=true --test_env=DISPLAY
Yerel bir emülatör veya cihazla test etme
Bazel ayrıca doğrudan yerel olarak başlatılan bir emülatörde veya bağlı cihazda test yapılmasını da destekler. Yerel test modunu etkinleştirmek için --test_strategy=exclusive
ve --test_arg=--device_broker_type=LOCAL_ADB_SERVER
işaretlerini geçin.
Birden fazla bağlı cihaz varsa --test_arg=--device_serial_number=$device_id
işaretini iletin. Burada $device_id
, adb devices
içinde listelenen cihazın/emülatörün kimliğidir.
Örnek projeler
Standart proje örnekleri arıyorsanız Espresso ve UIAutomator kullanan projeler için Android test örneklerine bakın.
Espresso kurulumu
Espresso (androidx.test.espresso
) ile kullanıcı arayüzü testleri yazarsanız Bazel çalışma alanınızı yaygın olarak kullanılan Espresso yapıları ve bağımlılıklarıyla ayarlamak için aşağıdaki snippet'leri kullanabilirsiniz:
androidx.test.espresso:espresso-core
androidx.test:rules
androidx.test:runner
javax.inject:javax.inject
org.hamcrest:java-hamcrest
junit:junit
Bu bağımlılıkları düzenlemenin bir yolu project root/BUILD.bazel
dosyanızda paylaşılan bir //:test_deps
kitaplığı oluşturmaktır:
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",
],
)
Ardından project root/WORKSPACE
komutuna gerekli bağımlılıkları ekleyin:
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",
],
)
Son olarak, test android_binary
hedefinize //:test_deps
bağımlılığını ekleyin:
android_binary(
name = "my_test_app",
instruments = "//path/to:app",
deps = [
"//:test_deps",
# ...
],
# ...
)
İpuçları
Test günlüklerini okuma
Başarısız testlere ait günlükleri yazdırmak için --test_output=errors
kodunu veya tüm test çıkışlarını yazdırmak için --test_output=all
kodunu kullanın. Tek bir test günlüğü arıyorsanız $PROJECT_ROOT/bazel-testlogs/path/to/InstrumentationTestTargetName
adresine gidin.
Örneğin, BasicSample
standart projesinin test günlükleri bazel-testlogs/ui/espresso/BasicSample/BasicSampleInstrumentationTest
içindedir. Çalıştırın:
tree bazel-testlogs/ui/espresso/BasicSample/BasicSampleInstrumentationTest
Bu işlem sonucunda şu çıkış elde edilir:
$ 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
Emülatör günlüklerini okuma
android_device
hedefleri için emülatör günlükleri, /tmp/
dizininde emulator_xxxxx.log
adıyla depolanır. Burada xxxxx
, rastgele oluşturulmuş bir karakter dizisidir.
En son emülatör günlüğünü bulmak için şu komutu kullanın:
ls -1t /tmp/emulator_*.log | head -n 1
Birden çok API düzeyiyle test etme
Birden fazla API düzeyinde test yapmak istiyorsanız her API düzeyi için test hedefleri oluşturmak üzere bir liste anlama özelliğini kullanabilirsiniz. Örneğin:
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]
Bilinen sorunlar
- Çatallı adb sunucusu işlemleri testlerden sonra sonlandırılmıyor
- APK oluşturma tüm platformlarda (Linux, macOS, Windows) çalışırken test yalnızca Linux'ta çalışır.
--config=local_adb
olsa bile kullanıcılarınandroid_instrumentation_test.target_device
belirtmesi gerekir.- Yerel cihaz veya emülatör kullanıyorsanız Bazel testten sonra APK'ları kaldırmaz. Şu komutu çalıştırarak paketleri temizleyin:
adb shell pm list
packages com.example.android.testing | cut -d ':' -f 2 | tr -d '\r' | xargs
-L1 -t adb uninstall