Uji Instrumentasi Android

Laporkan masalah Lihat sumber Per Malam · 7,4 kami. 7.3 · 7.2 · 7.1 · 7.0 · 6.5

Jika Anda baru menggunakan Bazel, mulailah dengan tutorial Mem-build Android dengan Bazel.

Menjalankan uji instrumentasi Android secara paralel

Gambar 1. Menjalankan uji instrumentasi Android paralel.

android_instrumentation_test memungkinkan developer menguji aplikasi mereka di emulator dan perangkat Android. Alat ini menggunakan API framework Android asli dan Android Test Library.

Untuk hermetisitas dan reproduksi, Bazel membuat dan meluncurkan emulator Android di sandbox, memastikan bahwa pengujian selalu berjalan dari status bersih. Setiap pengujian mendapatkan instance emulator yang terisolasi, sehingga pengujian dapat berjalan secara paralel tanpa meneruskan status di antara keduanya.

Untuk informasi selengkapnya tentang uji instrumentasi Android, lihat artikel pengembang dokumentasi tambahan.

Laporkan masalah di Issue Tracker GitHub.

Cara kerjanya

Saat Anda menjalankan bazel test pada target android_instrumentation_test untuk pertama kalinya, Bazel akan melakukan langkah-langkah berikut:

  1. Mem-build APK pengujian, APK yang sedang diuji, dan dependensi transitifnya
  2. Membuat, mem-booting, dan meng-cache status emulator bersih
  3. Memulai emulator
  4. Menginstal APK
  5. Menjalankan pengujian menggunakan Android Test Orchestrator
  6. Mematikan emulator
  7. Melaporkan hasil

Dalam pengujian berikutnya, Bazel mem-booting emulator dari status bersih yang di-cache yang dibuat pada langkah 2, sehingga tidak ada status yang tertinggal dari pengujian sebelumnya. Menyimpan ke cache status emulator juga mempercepat pengujian.

Prasyarat

Pastikan lingkungan Anda memenuhi prasyarat berikut:

  • Linux. Diuji pada Ubuntu 16.04, dan 18.04.

  • Bazel 0.12.0 atau yang lebih baru. Verifikasi versi dengan menjalankan bazel info release.

bazel info release

Hasilnya adalah output yang mirip dengan yang berikut ini:

release 4.1.0

Untuk memverifikasi bahwa KVM memiliki konfigurasi yang benar, jalankan:

apt-get install cpu-checker && kvm-ok

Jika pesan berikut tercetak, Anda memiliki konfigurasi yang benar:

INFO: /dev/kvm exists
KVM acceleration can be used
  • Xvfb. Untuk menjalankan pengujian headless (misalnya, di server CI), Bazel memerlukan framebuffer virtual X.

Untuk menginstalnya, jalankan:

apt-get install xvfb

Pastikan bahwa Xvfb sudah diinstal dengan benar dan diinstal di /usr/bin/Xvfb dengan menjalankan:

which Xvfb

Outputnya adalah sebagai berikut:

/usr/bin/Xvfb
  • Library 32-bit. Beberapa biner yang digunakan oleh infrastruktur pengujian adalah 32-bit, jadi pada komputer 64-bit, pastikan biner 32-bit dapat dijalankan. Sebagai Ubuntu, instal library 32-bit ini:
sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 lib32z1 libbz2-1.0:i386

Memulai

Berikut adalah grafik dependensi target android_instrumentation_test yang umum:

Grafik dependensi target pada uji instrumentasi Android

Gambar 2. Grafik dependensi target android_instrumentation_test.

File BUILD

Grafik diterjemahkan menjadi file BUILD seperti ini:

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",
    ]
    # ...
)

Atribut utama aturan android_instrumentation_test adalah:

  • test_app: Target android_binary. Target ini berisi kode uji dan dependensi seperti Espresso dan UIAutomator. android_binary yang dipilih target diperlukan untuk menentukan atribut instruments yang mengarah ke elemen lainnya android_binary, yang merupakan aplikasi yang sedang diuji.

  • target_device: Target android_device. Target ini menjelaskan spesifikasi emulator Android yang digunakan Bazel untuk membuat, meluncurkan, dan menjalankan pengujian. Lihat bagian tentang memilih Android perangkat untuk mengetahui informasi selengkapnya.

AndroidManifest.xml aplikasi pengujian harus menyertakan <instrumentation> menggunakan tag. Tag ini harus menentukan atribut untuk paket aplikasi target dan nama class yang sepenuhnya memenuhi syarat dari runner pengujian instrumentasi, androidx.test.runner.AndroidJUnitRunner.

Berikut adalah contoh AndroidTestManifest.xml untuk aplikasi pengujian:

<?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>

Dependensi WORKSPACE

Untuk menggunakan aturan ini, proyek Anda harus bergantung pada repositori:

  • @androidsdk: Android SDK. Download melalui Android Studio.

  • @android_test_support: Menghosting runner pengujian, peluncur emulator, dan target android_device. Anda dapat menemukan rilis terbaru di sini.

Aktifkan dependensi ini dengan menambahkan baris berikut ke WORKSPACE Anda file:

# 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()

Dependensi Maven

Untuk mengelola dependensi pada artefak Maven dari repositori, seperti Maven Google atau Maven Central, Anda harus menggunakan resolver Maven, seperti rules_jvm_external.

Bagian selanjutnya dari halaman ini menunjukkan cara menggunakan rules_jvm_external untuk menentukan dan mengambil dependensi dari repositori Maven.

Memilih target android_device

android_instrumentation_test.target_device menentukan perangkat Android tempat pengujian dijalankan. android_device target ini ditentukan di @android_test_support.

Misalnya, Anda dapat membuat kueri untuk sumber target tertentu dengan menjalankan:

bazel query --output=build @android_test_support//tools/android/emulated_devices/generic_phone:android_23_x86

Yang menghasilkan output yang terlihat mirip dengan:

# .../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",
)

Nama target perangkat menggunakan template ini:

@android_test_support//tools/android/emulated_devices/device_type:system_api_level_x86_qemu2

Untuk meluncurkan android_device, system_image untuk API yang dipilih level wajib diisi. Untuk mendownload image sistem, gunakan atribut tools/bin/sdkmanager. Misalnya, untuk mendownload image sistem untuk generic_phone:android_23_x86, jalankan $sdk/tools/bin/sdkmanager "system-images;android-23;default;x86".

Untuk melihat daftar lengkap target android_device yang didukung di @android_test_support, jalankan perintah berikut:

bazel query 'filter("x86_qemu2$", kind(android_device, @android_test_support//tools/android/emulated_devices/...:*))'

Bazel saat ini hanya mendukung emulator berbasis x86. Untuk performa yang lebih baik, gunakan QEMU2 target android_device bukan QEMU target.

Menjalankan pengujian

Untuk menjalankan pengujian, tambahkan baris ini ke file project root:/.bazelrc project Anda.

# 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

Kemudian, gunakan salah satu konfigurasi untuk menjalankan pengujian:

  • bazel test //my/test:target --config=gui
  • bazel test //my/test:target --config=headless
  • bazel test //my/test:target --config=local_device

Gunakan hanya satu konfigurasi atau pengujian akan gagal.

Pengujian headless

Dengan Xvfb, Anda dapat menguji dengan emulator tanpa antarmuka grafis, yang juga dikenal sebagai pengujian headless. Untuk menonaktifkan antarmuka grafis saat menjalankan pengujian, teruskan argumen pengujian --enable_display=false ke Bazel:

bazel test //my/test:target --test_arg=--enable_display=false

Pengujian GUI

Jika variabel lingkungan $DISPLAY disetel, dimungkinkan untuk mengaktifkan antarmuka grafis emulator saat pengujian berjalan. Untuk melakukannya, teruskan argumen pengujian ini ke Bazel:

bazel test //my/test:target --test_arg=--enable_display=true --test_env=DISPLAY

Menguji dengan emulator atau perangkat lokal

Bazel juga mendukung pengujian secara langsung pada emulator yang diluncurkan secara lokal atau perangkat seluler. Teruskan tanda --test_strategy=exclusive dan --test_arg=--device_broker_type=LOCAL_ADB_SERVER untuk mengaktifkan mode pengujian lokal. Jika ada lebih dari satu perangkat yang terhubung, teruskan penanda --test_arg=--device_serial_number=$device_id dengan $device_id adalah ID perangkat/emulator yang tercantum di adb devices.

Project contoh

Jika Anda mencari contoh project kanonis, lihat contoh pengujian Android untuk project yang menggunakan Espresso dan UIAutomator.

Penyiapan Espresso

Jika Anda menulis pengujian UI dengan Espresso (androidx.test.espresso), Anda dapat menggunakan cuplikan berikut untuk menyiapkan ruang kerja Bazel dengan daftar artefak Espresso yang umum digunakan dan dependensinya:

androidx.test.espresso:espresso-core
androidx.test:rules
androidx.test:runner
javax.inject:javax.inject
org.hamcrest:java-hamcrest
junit:junit

Salah satu cara untuk mengatur dependensi ini adalah dengan membuat library bersama //:test_deps dalam file project root/BUILD.bazel Anda:

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",
    ],
)

Kemudian, tambahkan dependensi yang diperlukan di 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",
    ],
)

Terakhir, dalam target android_binary pengujian Anda, tambahkan //:test_deps dependensi:

android_binary(
    name = "my_test_app",
    instruments = "//path/to:app",
    deps = [
        "//:test_deps",
        # ...
    ],
    # ...
)

Tips

Membaca log pengujian

Gunakan --test_output=errors untuk mencetak log untuk pengujian yang gagal, atau --test_output=all untuk mencetak semua output pengujian. Jika Anda mencari log pengujian individual, buka $PROJECT_ROOT/bazel-testlogs/path/to/InstrumentationTestTargetName.

Misalnya, log pengujian untuk project kanonis BasicSample berada di bazel-testlogs/ui/espresso/BasicSample/BasicSampleInstrumentationTest, jalankan:

tree bazel-testlogs/ui/espresso/BasicSample/BasicSampleInstrumentationTest

Hal ini menghasilkan output berikut:


$ 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

Membaca log emulator

Log emulator untuk target android_device disimpan di direktori /tmp/ dengan nama emulator_xxxxx.log, dengan xxxxx adalah urutan karakter yang dibuat secara acak.

Gunakan perintah ini untuk menemukan log emulator terbaru:

ls -1t /tmp/emulator_*.log | head -n 1

Menguji terhadap beberapa API level

Jika ingin menguji terhadap beberapa API level, Anda dapat menggunakan pemahaman daftar untuk membuat target pengujian untuk setiap API level. Contoh:

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]

Masalah umum

  • Proses server adb yang di-fork tidak dihentikan setelah pengujian
  • Meskipun build APK berfungsi di semua platform (Linux, macOS, Windows), pengujian hanya berfungsi di Linux.
  • Bahkan dengan --config=local_adb, pengguna tetap harus menentukan android_instrumentation_test.target_device.
  • Jika menggunakan perangkat atau emulator lokal, Bazel tidak meng-uninstal APK setelah melakukan pengujian. Bersihkan paket dengan menjalankan perintah ini:
adb shell pm list
packages com.example.android.testing | cut -d ':' -f 2 | tr -d '\r' | xargs
-L1 -t adb uninstall