Android इंस्ट्रूमेंटेशन टेस्ट

समस्या की शिकायत करें स्रोत देखें

अगर आपने Bazel का इस्तेमाल पहले कभी नहीं किया है, तो Bazel के साथ Android बनाना ट्यूटोरियल देखें.

साथ-साथ Android इंस्ट्रुमेंटेशन टेस्ट चलाना

पहला डायग्राम. पैरलल Android इंस्ट्रुमेंटेशन की जांच की जा रही है.

android_instrumentation_test की मदद से डेवलपर, Android एम्युलेटर और डिवाइसों पर अपने ऐप्लिकेशन की जांच कर सकते हैं. इसमें, Android टेस्ट लाइब्रेरी और Android फ़्रेमवर्क के असली एपीआई का इस्तेमाल किया जाता है.

हर्मेटिटी और रीप्रॉड्यूसिबिलिटी के लिए, Bazel सैंडबॉक्स में Android एम्युलेटर बनाता और लॉन्च करता है. इससे यह पक्का होता है कि टेस्ट हमेशा सही स्थिति में चलें. हर टेस्ट को एक अलग एम्युलेटर इंस्टेंस मिलता है, जिससे टेस्ट उनके बीच पास किए बिना ही साथ-साथ चल पाते हैं.

Android इंस्ट्रुमेंटेशन टेस्ट के बारे में ज़्यादा जानकारी के लिए, Android डेवलपर दस्तावेज़ देखें.

कृपया GitHub से जुड़ी समस्या को ट्रैक करने वाले टूल में समस्याओं की जानकारी दें.

यह कैसे काम करता है

पहली बार android_instrumentation_test के टारगेट पर bazel test चलाने पर, Bazel यह तरीका अपनाता है:

  1. टेस्ट APK, APK, और उनकी ट्रांज़िटिव डिपेंडेंसी बनाता है
  2. यह नीति, एम्युलेटर की स्थितियों को सेट करके, चालू करती है, कैश मेमोरी में सेव करती है, और चालू करती है
  3. एम्युलेटर शुरू करता है
  4. APK इंस्टॉल करता है
  5. Android टेस्ट ऑर्केस्ट्रेटर का इस्तेमाल करके टेस्ट करता है
  6. एम्युलेटर को बंद कर देता है
  7. नतीजों की रिपोर्ट करता है

बाद में टेस्ट करने पर, Bazel, एम्युलेटर को दूसरे चरण में बनाए गए, कैश मेमोरी में सेव किए गए साफ़ स्टेटस से चालू करता है. ऐसा इसलिए, ताकि पिछली बार चलाए गए डेटा की कोई स्थिति न बची हो. कैश मेमोरी में सेव होने वाले एम्युलेटर की स्थिति में भी, टेस्ट तेज़ हो जाते हैं.

ज़रूरी शर्तें

पक्का करें कि आपका एनवायरमेंट इन शर्तों को पूरा करता हो:

  • Linux. Ubuntu 16.04, और 18.04 पर टेस्ट किया गया.

  • Bazel 0.12.0 या उसके बाद के वर्शन. bazel info release चलाकर वर्शन की पुष्टि करें.

bazel info release

इससे, आउटपुट कुछ ऐसा मिलता है:

release 4.1.0

यह पुष्टि करने के लिए कि केवीएम का कॉन्फ़िगरेशन सही है, इसे चलाएं:

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

YouTube TV का इस्तेमाल शुरू करना

यहां android_instrumentation_test का सामान्य टारगेट डिपेंडेंसी ग्राफ़ दिया गया है:

Android इंस्ट्रुमेंटेशन टेस्ट पर टारगेट डिपेंडेंसी ग्राफ़

दूसरी इमेज. किसी android_instrumentation_test का टारगेट डिपेंडेंसी ग्राफ़.

बिल्ड फ़ाइल

ग्राफ़, 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. इस टारगेट में Android Emulator की उन खास बातों के बारे में बताया गया है जिनका इस्तेमाल Bazel, टेस्ट बनाने, लॉन्च करने, और चलाने के लिए करता है. ज़्यादा जानकारी के लिए, 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 आर्टफ़ैक्ट की डिपेंडेंसी को मैनेज करने के लिए, आपको rules_jvm_external जैसे मेवन रिज़ॉल्वर का इस्तेमाल करना चाहिए. जैसे, Google Maven या Maven Central.

इस पेज के बाकी हिस्से में, मेवन रिपॉज़िटरी से डिपेंडेंसी पाने और डिपेंडेंसी पाने के लिए 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 को Bazel को पास करें:

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

जीयूआई टेस्टिंग

अगर $DISPLAY एनवायरमेंट वैरिएबल सेट किया गया है, तो टेस्ट के दौरान भी एम्युलेटर के ग्राफ़िकल इंटरफ़ेस को चालू किया जा सकता है. ऐसा करने के लिए, Bzel को ये जांच वाले तर्क पास करें:

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 में दिए गए डिवाइस/एम्युलेटर का आईडी है.

सैंपल प्रोजेक्ट

अगर आपको कैननिकल प्रोजेक्ट के सैंपल चाहिए, तो Espresso और UIAutomator का इस्तेमाल करने वाले प्रोजेक्ट के लिए, Android टेस्टिंग के सैंपल देखें.

एस्प्रेसो सेटअप

अगर Espresso (androidx.test.espresso) की मदद से यूज़र इंटरफ़ेस (यूआई) टेस्ट लिखा जाता है, तो आम तौर पर इस्तेमाल होने वाले एस्प्रेसो आर्टफ़ैक्ट और उनकी डिपेंडेंसी के साथ अपना बेज़ल फ़ाइल फ़ोल्डर सेट अप करने के लिए, इन स्निपेट का इस्तेमाल किया जा सकता है:

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 टारगेट के लिए एम्युलेटर लॉग, emulator_xxxxx.log नाम के साथ /tmp/ डायरेक्ट्री में सेव किए जाते हैं. इसमें 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]

आम तौर पर होने वाली समस्याएं

  • टेस्ट के बाद, फ़ोर्क किए गए 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