अगर आपने Bazel का इस्तेमाल पहले कभी नहीं किया है, तो Bazel की मदद से Android बनाना ट्यूटोरियल से शुरुआत करें.
पहली इमेज. साथ-साथ चलने वाले Android इंस्ट्रुमेंटेशन की जांच कर रहे हैं.
android_instrumentation_test
की मदद से, डेवलपर अपने ऐप्लिकेशन को Android एमुलेटर और डिवाइसों पर टेस्ट कर सकते हैं.
यह असल Android फ़्रेमवर्क एपीआई और Android टेस्ट लाइब्रेरी का इस्तेमाल करता है.
Bazel, सैंडबॉक्स में Android इम्युलेटर बनाता और लॉन्च करता है. इससे, यह पक्का किया जाता है कि टेस्ट हमेशा एक ही स्टेटस में चलें. हर टेस्ट के लिए, एक अलग इम्यूलेटर इंस्टेंस मिलता है. इससे टेस्ट, एक-दूसरे के स्टेटस को पास किए बिना, एक साथ चल सकते हैं.
Android इंस्ट्रुमेंटेशन टेस्ट के बारे में ज़्यादा जानकारी के लिए, Android डेवलपर दस्तावेज़ देखें.
कृपया GitHub में समस्या को ट्रैक करने वाले टूल में समस्याओं की शिकायत करें.
यह कैसे काम करता है
जब किसी android_instrumentation_test
टारगेट पर पहली बार bazel test
को चलाया जाता है, तो Bazel यह तरीका अपनाता है:
- टेस्ट APK, जांचा जा रहा APK, और उनकी ट्रांज़िशन डिपेंडेंसी बनाता है
- क्लीन एम्युलेटर स्टेट को बनाता है, चालू करता है, और कैश मेमोरी में सेव करता है
- एम्युलेटर शुरू करता है
- APK इंस्टॉल करता है
- Android Test Orchestrator का इस्तेमाल करके टेस्ट चलाता है
- एम्युलेटर को बंद करता है
- नतीजे दिखाता है
बाद के टेस्ट रन में, Bazel एमुलेटर को दूसरे चरण में बनाई गई क्लीन और कैश मेमोरी में सेव की गई स्थिति से बूट करता है, ताकि पिछले रन से कोई स्टेटस न बचे. एमुलेटर की स्थिति को कैश मेमोरी में सेव करने से, टेस्ट रन की प्रोसेस तेज़ होती है.
ज़रूरी शर्तें
पक्का करें कि आपका एनवायरमेंट, यहां दी गई ज़रूरी शर्तों को पूरा करता हो:
Linux. Ubuntu 16.04 और 18.04 पर टेस्ट किया गया.
Bazel 0.12.0 या उसके बाद का वर्शन.
bazel info release
को चलाकर, वर्शन की पुष्टि करें.
bazel info release
इससे आउटपुट कुछ ऐसा मिलता है:
release 4.1.0
- केवीएम. Babel के लिए यह ज़रूरी है कि Linux पर केवीएम के साथ एम्युलेटर के लिए हार्डवेयर से तेज़ी लाएं. Ubuntu के लिए, इंस्टॉल करने के इन निर्देशों का पालन करें.
यह पुष्टि करने के लिए कि 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
का एक सामान्य टारगेट डिपेंडेंसी ग्राफ़ दिया गया है:
दूसरी इमेज. 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
टारगेट के लिए, किसी दूसरेandroid_binary
पर ले जाने वालाinstruments
एट्रिब्यूट तय करना ज़रूरी है. यह वहandroid_binary
होता है जिसे टेस्ट किया जा रहा है.target_device
:android_device
टारगेट. इस टारगेट में 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>
वर्कस्पेस डिपेंडेंसी
इस नियम का इस्तेमाल करने के लिए, आपके प्रोजेक्ट को इन बाहरी रिपॉज़िटरी पर निर्भर होना होगा:
@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 डिपेंडेंसी
Google Maven या Maven Central जैसी रिपॉज़िटरी से Maven आर्टफ़ैक्ट पर डिपेंडेंसी मैनेज करने के लिए, आपको Maven रिज़ॉल्वर का इस्तेमाल करना चाहिए. जैसे, rules_jvm_external
.
इस पेज के बाकी हिस्से में, मेवन डेटा स्टोर करने की जगहों से डिपेंडेंसी का समाधान करने और उसे फ़ेच करने के लिए, rules_jvm_external
का इस्तेमाल करने का तरीका बताया गया है.
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
लॉन्च करने के लिए, चुने गए एपीआई लेवल के लिए system_image
ज़रूरी है. सिस्टम इमेज डाउनलोड करने के लिए, Android SDK के
tools/bin/sdkmanager
का इस्तेमाल करें. उदाहरण के लिए, generic_phone:android_23_x86
के लिए सिस्टम इमेज डाउनलोड करने के लिए, $sdk/tools/bin/sdkmanager
"system-images;android-23;default;x86"
चलाएं.
@android_test_support
में काम करने वाले android_device
टारगेट की पूरी सूची देखने के लिए, यह कमांड चलाएं:
bazel query 'filter("x86_qemu2$", kind(android_device, @android_test_support//tools/android/emulated_devices/...:*))'
फ़िलहाल, Bazel सिर्फ़ x86-आधारित एम्युलेटर के साथ काम करता है. बेहतर परफ़ॉर्मेंस के लिए, QEMU
के बजाय QEMU2
android_device
टारगेट का इस्तेमाल करें.
टेस्ट चलाना
जांच करने के लिए, अपने प्रोजेक्ट की
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
को Basel में पास करें:
bazel test //my/test:target --test_arg=--enable_display=false
जीयूआई टेस्टिंग
अगर $DISPLAY
एनवायरमेंट वैरिएबल सेट है, तो टेस्ट के चलने के दौरान, एमुलेटर के ग्राफ़िकल इंटरफ़ेस को चालू किया जा सकता है. इसके लिए, Bazel को ये टेस्ट आर्ग्युमेंट पास करें:
bazel test //my/test:target --test_arg=--enable_display=true --test_env=DISPLAY
स्थानीय एम्युलेटर या डिवाइस से जांच करना
Basel को टेस्ट करने के लिए, स्थानीय तौर पर लॉन्च किए गए एम्युलेटर या कनेक्ट किए गए
डिवाइस का इस्तेमाल भी किया जा सकता है. स्थानीय टेस्टिंग मोड चालू करने के लिए, फ़्लैग
--test_strategy=exclusive
और
--test_arg=--device_broker_type=LOCAL_ADB_SERVER
पास करें.
अगर एक से ज़्यादा डिवाइस कनेक्ट हैं, तो फ़्लैग --test_arg=--device_serial_number=$device_id
पास करें. यहां $device_id
, adb devices
में दिए गए डिवाइस/एम्युलेटर का आईडी है.
सैंपल प्रोजेक्ट
अगर आपको कैननिकल प्रोजेक्ट के सैंपल चाहिए, तो Espresso और UIAutomator का इस्तेमाल करने वाले प्रोजेक्ट के लिए, Android टेस्टिंग के सैंपल देखें.
एस्प्रेसो सेटअप
अगर Espresso
(androidx.test.espresso
) का इस्तेमाल करके यूज़र इंटरफ़ेस (यूआई) टेस्ट लिखे जाते हैं, तो यहां दिए गए स्निपेट का इस्तेमाल करके, आम तौर पर इस्तेमाल किए जाने वाले Espresso आर्टफ़ैक्ट और उनकी डिपेंडेंसी की सूची के साथ अपना Bazel वर्कस्पेस सेट अप किया जा सकता है:
androidx.test.espresso:espresso-core
androidx.test:rules
androidx.test:runner
javax.inject:javax.inject
org.hamcrest:java-hamcrest
junit:junit
इन डिपेंडेंसी को व्यवस्थित करने का एक तरीका यह है कि अपनी project root/BUILD.bazel
फ़ाइल में //:test_deps
शेयर की गई लाइब्रेरी बनाएं:
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_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]
पहले से मालूम समस्याएं
- जांच के बाद, Forked adb सर्वर की प्रोसेस को बंद नहीं किया जाता
- हालांकि, APK बिल्डिंग सभी प्लैटफ़ॉर्म (Linux, macOS, Windows) पर काम करती है, लेकिन टेस्टिंग सिर्फ़ Linux पर काम करती है.
--config=local_adb
के साथ भी, उपयोगकर्ताओं को अब भीandroid_instrumentation_test.target_device
की जानकारी देनी होगी.- अगर किसी लोकल डिवाइस या एम्युलेटर का इस्तेमाल किया जा रहा है, तो Baze, जांच के बाद APKs अनइंस्टॉल नहीं करता. इस निर्देश को चलाकर, पैकेज हटाएं:
adb shell pm list
packages com.example.android.testing | cut -d ':' -f 2 | tr -d '\r' | xargs
-L1 -t adb uninstall