Android インストルメンテーション テスト

<ph type="x-smartling-placeholder"></ph> 問題を報告する ソースを表示 夜間 · 7.3 · 7.2 · 7.1 · 7.0 · 6.5

Bazel を初めて使用する場合は、「Building Android with Bazel のチュートリアルをご覧ください。

Android インストルメンテーション テストの並列実行

図 1. Android インストルメンテーション テストの並列実行

android_instrumentation_test を使用すると、デベロッパーは Android Emulator やデバイスでアプリをテストできます。 実際の Android フレームワーク API と Android テスト ライブラリを利用します。

密閉性と再現性を確保するため、Bazel は Android を作成して起動します。 サンドボックス内でエミュレータを使用して、テストを常にクリーンな状態から実行できます。各 分離されたエミュレータ インスタンスを取得して、テストを並行して実行できる 状態を受け渡す必要はありません

Android インストルメンテーション テストについて詳しくは、Android 開発者 ドキュメントをご覧ください

GitHub の Issue Tracker で問題を報告してください。

仕組み

同じサービスの android_instrumentation_test ターゲットで bazel test を実行すると、 最初に Bazel は次の処理を行います。

  1. テスト APK、テスト対象の APK、およびそれらの推移的依存関係をビルドします
  2. クリーンなエミュレータの状態を作成、起動、キャッシュに保存
  3. エミュレータを起動します。
  4. APK をインストールする
  5. Android Test Orchestrator を使用してテストを実行する
  6. エミュレータをシャットダウンする
  7. 結果を報告します。

その後のテスト実行では、Bazel はエミュレータをキャッシュされたクリーンな状態から起動します。 以前の実行で残された状態はありません。キャッシュ エミュレータの状態によってテスト実行も高速化されます。

前提条件

環境が次の前提条件を満たしていることを確認します。

  • 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

インストールするには、次のコマンドを実行します。

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 インストルメンテーション テストのターゲット依存関係グラフ

図 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 ターゲット。このターゲットは、 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 の依存関係

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。たとえば、Cloud Shell のシステム イメージをダウンロードするには、 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 ベースのエミュレータのみをサポートしています。パフォーマンスを向上させるには、 目標は 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

使用する構成は 1 つだけにしましょう。そうしないと、テストは失敗します。

ヘッドレス テスト

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 では、ローカルで起動したエミュレータや Google Cloud の接続されている ダウンロードしますフラグを渡す --test_strategy=exclusive--test_arg=--device_broker_type=LOCAL_ADB_SERVER: ローカルテストモードを有効にします。 接続されているデバイスが複数ある場合は、フラグを渡します。 --test_arg=--device_serial_number=$device_id$device_id は ID) adb devices にリストされているデバイス/エミュレータ

サンプル プロジェクト

正規のプロジェクト サンプルをお探しの場合は、Android のテスト サンプル Espresso と UIAutomator を使用するプロジェクトでは

Espresso のセットアップ

Espresso を使用して UI テストを作成する場合 (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

このような依存関係を整理する 1 つの方法は、//: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