如果您是 Bazel 新手,請先從使用 Bazel 教學課程。
圖 1. 執行平行 Android 檢測設備測試。
android_instrumentation_test
敬上
可讓開發人員在 Android 模擬器和裝置上測試應用程式。
它使用實際的 Android 架構 API 和 Android 測試程式庫。
Bazel 基於特徵碼和可重現性建立並啟動 Android 在沙箱中啟動模擬器,確保測試一律從乾淨狀態執行。每項 測試取得隔離的模擬器執行個體,可讓測試平行執行 而不會在容器之間傳遞狀態
如要進一步瞭解 Android 檢測設備測試,請參閱 Android 開發人員 說明文件。
請在 GitHub 問題追蹤工具中回報問題。
運作方式
當您在 android_instrumentation_test
目標上執行 bazel test
時
Bazel 會執行下列步驟:
- 建構測試 APK、測試中的 APK 及其轉換依附元件
- 建立、啟動及快取清除模擬器狀態
- 啟動模擬器
- 安裝 APK
- 使用 Android Test Orchestrator 執行測試
- 關閉模擬器
- 回報結果
Bazel 在後續的測試中執行時,會從乾淨的快取狀態啟動模擬器 建立在步驟 2 中,因此之前的執行作業中不會有任何剩餘狀態。快取 模擬器狀態也會加快測試執行速度。
必要條件
確認環境滿足下列必要條件:
Linux。在 Ubuntu 16.04 和 18.04 上進行測試。
Bazel 0.12.0 以上版本。執行
bazel info release
來驗證版本。
bazel info release
這會產生類似以下的輸出內容:
release 4.1.0
如要確認 KVM 設定是否正確,請執行:
apt-get install cpu-checker && kvm-ok
如果系統顯示下列訊息,表示設定正確無誤:
INFO: /dev/kvm exists
KVM acceleration can be used
- Xvfb。如要執行無頭測試 (例如在持續整合伺服器上),Bazel 需要 X 虛擬影格緩衝區。
如要安裝這個套件,請執行:
apt-get install xvfb
確認 Xvfb
已正確安裝且安裝在 /usr/bin/Xvfb
方法是執行:
which Xvfb
輸出內容如下:
/usr/bin/Xvfb
- 32 位元程式庫。測試基礎架構使用的部分二進位檔如下 如果是 32 位元的機器,因此請確保可以在 64 位元機器上執行 32 位元的二進位檔。適用對象 Ubuntu,請安裝以下 32 位元程式庫:
sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 lib32z1 libbz2-1.0:i386
開始使用
以下是 android_instrumentation_test
的一般目標依附元件圖表:
圖 2. android_instrumentation_test
的目標依附元件圖表。
BUILD 檔案
圖表會轉譯為 BUILD
檔案,如下所示:
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
的主要屬性為:
test_app
:android_binary
目標。這個目標內含測試程式碼 Espresso 和 UIAutomator 等依附元件。所選android_binary
必須指定目標,才能指定指向另一個instruments
屬性android_binary
,也就是接受測試的應用程式。target_device
:android_device
目標。這個目標描述了 Bazel 使用的 Android 模擬器的規格 並進行測試請參閱選擇 Android 的相關章節 裝置。
測試應用程式的 AndroidManifest.xml
必須包含 <instrumentation>
標記。
此標記必須指定目標應用程式套件的屬性,
檢測設備測試執行工具的完整類別名稱,
androidx.test.runner.AndroidJUnitRunner
。
以下是測試應用程式的 AndroidTestManifest.xml
範例:
<?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 依附元件
如要使用這項規則,您的專案必須依賴這些外部項目 存放區:
@androidsdk
:Android SDK。請透過 Android Studio 下載。@android_test_support
:代管測試執行器、模擬器啟動器和android_device
個目標。您可以查看最新版本 此處。
將下列程式碼新增至 WORKSPACE
以啟用這些依附元件
檔案:
# 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 依附元件
用於管理 Maven 構件的存放區來自存放區,例如 Google
Maven 或 Maven Central
您應該使用 Maven 解析器,例如
rules_jvm_external
。
本頁其餘部分將說明如何使用 rules_jvm_external
執行下列操作:
解析及擷取 Maven 存放區中的依附元件。
選擇 android_device 目標
android_instrumentation_test.target_device
會指定要使用哪一部 Android 裝置
及執行測試這些 android_device
個目標已定義於
@android_test_support
。
舉例來說,您可以執行下列指令,查詢特定目標的來源:
bazel query --output=build @android_test_support//tools/android/emulated_devices/generic_phone:android_23_x86
輸出的結果看起來會類似這樣:
# .../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",
)
指定裝置名稱使用這個範本:
@android_test_support//tools/android/emulated_devices/device_type:system_api_level_x86_qemu2
為啟動 android_device
,所選 API 的 system_image
必須提供層級。如要下載系統映像檔,請使用 Android SDK 的
tools/bin/sdkmanager
。舉例來說,如要下載應用程式的系統映像檔
generic_phone:android_23_x86
,執行 $sdk/tools/bin/sdkmanager
"system-images;android-23;default;x86"
。
如要查看支援的android_device
目標完整清單,請前往
@android_test_support
,執行下列指令:
bazel query 'filter("x86_qemu2$", kind(android_device, @android_test_support//tools/android/emulated_devices/...:*))'
Bazel 目前僅支援 x86 型模擬器。如要提高效能,請使用
QEMU2
這是android_device
目標,而非 QEMU
個。
執行測試
如要執行測試,請在專案的
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
然後使用其中一種設定執行測試:
bazel test //my/test:target --config=gui
bazel test //my/test:target --config=headless
bazel test //my/test:target --config=local_device
請只使用一項設定,否則測試就會失敗。
無頭測試
使用 Xvfb
,即可在沒有圖形化的模擬器上進行測試
又稱無頭測試停用圖形介面
執行測試時,請將測試引數 --enable_display=false
傳遞至 Bazel:
bazel test //my/test:target --test_arg=--enable_display=false
GUI 測試
如果已設定 $DISPLAY
環境變數,則可以啟用
測試執行期間的模擬器圖形介面。方法很簡單
對 Bazel 使用以下測試引數:
bazel test //my/test:target --test_arg=--enable_display=true --test_env=DISPLAY
使用本機模擬器或裝置進行測試
Bazel 也支援直接在本機啟動的模擬器上進行測試,
裝置。通過標記
「--test_strategy=exclusive
」和
如要啟用本機測試模式,請--test_arg=--device_broker_type=LOCAL_ADB_SERVER
。
如有多部已連結的裝置,請傳送這個標記
--test_arg=--device_serial_number=$device_id
,其中 $device_id
是
adb devices
中列出的裝置/模擬器。
專案範例
如需標準專案範例,請參閱 Android 測試 範例 使用 Espresso 和 UIAutomator 的專案
Espresso 設定
使用 Espresso 編寫 UI 測試時
(androidx.test.espresso
),您可以使用下列程式碼片段設定
Bazel 工作區,當中列出常用的 Espresso 構件及其
依附元件:
androidx.test.espresso:espresso-core
androidx.test:rules
androidx.test:runner
javax.inject:javax.inject
org.hamcrest:java-hamcrest
junit:junit
如要整理這些依附元件,其中一種方法是建立共用 //:test_deps
加入 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",
],
)
然後在 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",
],
)
最後,在測試 android_binary
目標中加入 //:test_deps
依附元件:
android_binary(
name = "my_test_app",
instruments = "//path/to:app",
deps = [
"//:test_deps",
# ...
],
# ...
)
提示
讀取測試記錄
使用 --test_output=errors
列印失敗測試的記錄;或
使用 --test_output=all
列印所有測試輸出內容。如果您在尋找
個別測試記錄,請前往
$PROJECT_ROOT/bazel-testlogs/path/to/InstrumentationTestTargetName
。
舉例來說,BasicSample
標準專案的測試記錄位於
bazel-testlogs/ui/espresso/BasicSample/BasicSampleInstrumentationTest
,執行:
tree bazel-testlogs/ui/espresso/BasicSample/BasicSampleInstrumentationTest
這會產生以下輸出內容:
$ 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
讀取模擬器記錄
android_device
目標的模擬器記錄會儲存在 /tmp/
中
名為 emulator_xxxxx.log
的目錄,其中 xxxxx
是
隨機產生的字元序列
使用這個指令尋找最新的模擬器記錄:
ls -1t /tmp/emulator_*.log | head -n 1
針對多個 API 級別進行測試
如果您想要針對多個 API 級別進行測試,可以使用一份清單 為各個 API 級別建立測試目標例如:
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]
已知問題
- 分支的 ADB 伺服器程序不會在 測試
- 雖然 APK 建構可以在所有平台 (Linux、macOS、Windows) 上運作,但測試 僅適用於 Linux。
- 即使使用
--config=local_adb
,使用者仍須指定android_instrumentation_test.target_device
。 - 如果您使用本機裝置或模擬器,Bazel 不會在之後解除安裝 APK 進行測試。執行下列指令來清理套件:
adb shell pm list
packages com.example.android.testing | cut -d ':' -f 2 | tr -d '\r' | xargs
-L1 -t adb uninstall