jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 1 | --- |
| 2 | layout: documentation |
| 3 | title: Android Instrumentation Tests |
| 4 | --- |
| 5 | |
| 6 | # Android Instrumentation Tests |
| 7 | |
| 8 | _If you're new to Bazel, please start with the [Building Android with |
Jingwen Chen | 0f4544d | 2018-12-14 16:28:16 -0800 | [diff] [blame] | 9 | Bazel](tutorial/android-app.html) tutorial._ |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 10 | |
| 11 |  |
| 12 | |
Jingwen Chen | 0f4544d | 2018-12-14 16:28:16 -0800 | [diff] [blame] | 13 | [`android_instrumentation_test`](be/android.html#android_instrumentation_test) |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 14 | allows developers to test their apps on Android emulators and devices. |
| 15 | It utilizes real Android framework APIs and the Android Test Library. |
| 16 | |
| 17 | For hermeticity and reproducibility, Bazel creates and launches Android |
| 18 | emulators in a sandbox, ensuring that tests always run from a clean state. Each |
| 19 | test gets an isolated emulator instance, allowing tests to run in parallel |
| 20 | without passing states between them. |
| 21 | |
| 22 | For more information on Android instrumentation tests, check out the [Android |
| 23 | developer |
| 24 | documentation](https://developer.android.com/training/testing/unit-testing/instrumented-unit-tests.html). |
| 25 | |
jingwen | 5ff94b7 | 2018-08-08 13:04:52 -0700 | [diff] [blame] | 26 | Please file issues in the [GitHub issue tracker](https://github.com/bazelbuild/bazel/issues). |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 27 | |
Googler | 1403a16 | 2021-01-22 13:42:50 -0800 | [diff] [blame] | 28 | ## How it works |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 29 | |
| 30 | When you run `bazel test` on an `android_instrumentation_test` target for the |
| 31 | first time, Bazel performs the following steps: |
| 32 | |
| 33 | 1. Builds the test APK, APK under test, and their transitive dependencies |
| 34 | 2. Creates, boots, and caches clean emulator states |
| 35 | 3. Starts the emulator |
| 36 | 4. Installs the APKs |
| 37 | 5. Runs tests utilizing the [Android Test Orchestrator](https://developer.android.com/training/testing/junit-runner.html#using-android-test-orchestrator) |
| 38 | 6. Shuts down the emulator |
| 39 | 7. Reports the results |
| 40 | |
| 41 | In subsequent test runs, Bazel boots the emulator from the clean, cached state |
| 42 | created in step 2, so there are no leftover states from previous runs. Caching |
| 43 | emulator state also speeds up test runs. |
| 44 | |
Googler | 1403a16 | 2021-01-22 13:42:50 -0800 | [diff] [blame] | 45 | ## Prerequisites |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 46 | |
jingwen | 7c70d82 | 2019-01-08 15:12:29 -0800 | [diff] [blame] | 47 | Ensure your environment satisfies the following prerequisites: |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 48 | |
Philipp Wollermann | 927d32d | 2019-06-17 13:35:55 -0700 | [diff] [blame] | 49 | - **Linux**. Tested on Ubuntu 16.04, and 18.04. |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 50 | |
| 51 | - **Bazel 0.12.0** or later. Verify the version by running `bazel info release`. |
| 52 | |
| 53 | ``` |
| 54 | $ bazel info release |
| 55 | release 0.12.0 |
| 56 | ``` |
| 57 | |
| 58 | - **KVM**. Bazel requires emulators to have [hardware |
| 59 | acceleration](https://developer.android.com/studio/run/emulator-acceleration.html#accel-check) |
| 60 | with KVM on Linux. You can follow these |
| 61 | [installation instructions](https://help.ubuntu.com/community/KVM/Installation) |
| 62 | for Ubuntu. Run `apt-get install cpu-checker && kvm-ok` to verify that KVM has |
| 63 | the correct configuration. If it prints the following message, you're good to |
| 64 | go: |
| 65 | |
| 66 | ``` |
| 67 | $ kvm-ok |
| 68 | INFO: /dev/kvm exists |
| 69 | KVM acceleration can be used |
| 70 | ``` |
| 71 | |
| 72 | - **Xvfb**. To run headless tests (for example, on CI servers), Bazel requires |
| 73 | the [X virtual framebuffer](https://www.x.org/archive/X11R7.6/doc/man/man1/Xvfb.1.xhtml). |
| 74 | Install it by running `apt-get install xvfb`. Verify that `Xvfb` is installed |
| 75 | correctly by running `which Xvfb` and ensure that it's installed at |
| 76 | `/usr/bin/Xvfb`: |
| 77 | |
| 78 | ``` |
| 79 | $ which Xvfb |
| 80 | /usr/bin/Xvfb |
| 81 | ``` |
| 82 | |
ahumesky | c789d78 | 2021-03-09 15:45:40 -0800 | [diff] [blame] | 83 | - **32-bit Libraries**. Some of the binaries used by the test infrastructure are |
| 84 | 32-bit, so on 64-bit machines, ensure that 32-bit binaries can be run. For |
| 85 | Ubuntu, install these 32-bit libraries: |
| 86 | |
| 87 | ``` |
| 88 | sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 lib32z1 libbz2-1.0:i386 |
| 89 | ``` |
| 90 | |
Googler | 1403a16 | 2021-01-22 13:42:50 -0800 | [diff] [blame] | 91 | ## Getting started |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 92 | |
| 93 | Here is a typical target dependency graph of an `android_instrumentation_test`: |
| 94 | |
| 95 |  |
| 96 | |
Googler | 07dde6a | 2021-05-21 09:30:32 -0700 | [diff] [blame] | 97 | ### BUILD file |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 98 | |
| 99 | The graph translates into a `BUILD` file like this: |
| 100 | |
| 101 | ```python |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 102 | android_instrumentation_test( |
| 103 | name = "my_test", |
| 104 | test_app = ":my_test_app", |
Googler | c38e667 | 2019-04-12 14:55:08 -0700 | [diff] [blame] | 105 | target_device = "@android_test_support//tools/android/emulated_devices/generic_phone:android_23_x86", |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 106 | ) |
| 107 | |
| 108 | # Test app and library |
| 109 | android_binary( |
| 110 | name = "my_test_app", |
| 111 | instruments = ":my_app", |
| 112 | manifest = "AndroidTestManifest.xml", |
| 113 | deps = [":my_test_lib"], |
| 114 | # ... |
| 115 | ) |
| 116 | |
| 117 | android_library( |
| 118 | name = "my_test_lib", |
| 119 | srcs = glob(["javatest/**/*.java"]), |
| 120 | deps = [ |
| 121 | ":my_app_lib", |
Jingwen Chen | 20b544a | 2019-03-21 12:52:28 -0700 | [diff] [blame] | 122 | "@maven//:androidx_test_core", |
| 123 | "@maven//:androidx_test_runner", |
| 124 | "@maven//:androidx_test_espresso_espresso_core", |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 125 | ], |
| 126 | # ... |
| 127 | ) |
| 128 | |
| 129 | # Target app and library under test |
| 130 | android_binary( |
| 131 | name = "my_app", |
| 132 | manifest = "AndroidManifest.xml", |
| 133 | deps = [":my_app_lib"], |
| 134 | # ... |
| 135 | ) |
| 136 | |
| 137 | android_library( |
| 138 | name = "my_app_lib", |
| 139 | srcs = glob(["java/**/*.java"]), |
| 140 | deps = [ |
Jingwen Chen | 20b544a | 2019-03-21 12:52:28 -0700 | [diff] [blame] | 141 | "@maven//:androidx_appcompat_appcompat", |
| 142 | "@maven//:androidx_annotation_annotation", |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 143 | ] |
| 144 | # ... |
| 145 | ) |
| 146 | ``` |
| 147 | |
| 148 | The main attributes of the rule `android_instrumentation_test` are: |
| 149 | |
| 150 | - `test_app`: An `android_binary` target. This target contains test code and |
| 151 | dependencies like Espresso and UIAutomator. The selected `android_binary` |
| 152 | target is required to specify an `instruments` attribute pointing to another |
| 153 | `android_binary`, which is the app under test. |
| 154 | |
| 155 | - `target_device`: An `android_device` target. This target describes the |
| 156 | specifications of the Android emulator which Bazel uses to create, launch and |
| 157 | run the tests. See the [section on choosing an Android |
| 158 | device](#choosing-an-android_device) for more information. |
| 159 | |
Jingwen Chen | 20b544a | 2019-03-21 12:52:28 -0700 | [diff] [blame] | 160 | The test app's `AndroidManifest.xml` must include [an `<instrumentation>` |
| 161 | tag](https://developer.android.com/studio/test/#configure_instrumentation_manifest_settings). |
jingwen | 2734ceb | 2018-08-14 15:32:49 -0700 | [diff] [blame] | 162 | This tag must specify the attributes for the **package of the target app** and |
| 163 | the **fully qualified class name of the instrumentation test runner**, |
Jingwen Chen | 20b544a | 2019-03-21 12:52:28 -0700 | [diff] [blame] | 164 | `androidx.test.runner.AndroidJUnitRunner`. |
jingwen | 2734ceb | 2018-08-14 15:32:49 -0700 | [diff] [blame] | 165 | |
| 166 | Here is an example `AndroidTestManifest.xml` for the test app: |
| 167 | |
| 168 | ```xml |
| 169 | <?xml version="1.0" encoding="UTF-8"?> |
| 170 | <manifest xmlns:android="http://schemas.android.com/apk/res/android" |
| 171 | xmlns:tools="http://schemas.android.com/tools" |
| 172 | package="com.example.android.app.test" |
| 173 | android:versionCode="1" |
| 174 | android:versionName="1.0"> |
| 175 | |
| 176 | <instrumentation |
Jingwen Chen | 20b544a | 2019-03-21 12:52:28 -0700 | [diff] [blame] | 177 | android:name="androidx.test.runner.AndroidJUnitRunner" |
jingwen | 2734ceb | 2018-08-14 15:32:49 -0700 | [diff] [blame] | 178 | android:targetPackage="com.example.android.app" /> |
| 179 | |
| 180 | <uses-sdk |
| 181 | android:minSdkVersion="16" |
| 182 | android:targetSdkVersion="27" /> |
| 183 | |
| 184 | <application > |
| 185 | <!-- ... --> |
| 186 | </application> |
| 187 | </manifest> |
| 188 | ``` |
| 189 | |
Googler | 07dde6a | 2021-05-21 09:30:32 -0700 | [diff] [blame] | 190 | ### WORKSPACE dependencies |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 191 | |
| 192 | In order to use this rule, your project needs to depend on these external |
| 193 | repositories: |
| 194 | |
| 195 | - `@androidsdk`: The Android SDK. Download this through Android Studio. |
| 196 | |
| 197 | - `@android_test_support`: Hosts the test runner, emulator launcher, and |
Jingwen Chen | 20b544a | 2019-03-21 12:52:28 -0700 | [diff] [blame] | 198 | `android_device` targets. You can find the [latest release |
| 199 | here](https://github.com/android/android-test/releases) |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 200 | |
Jingwen Chen | 20b544a | 2019-03-21 12:52:28 -0700 | [diff] [blame] | 201 | Enable these dependencies by adding the following lines to your `WORKSPACE` |
| 202 | file: |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 203 | |
| 204 | ```python |
| 205 | # Android SDK |
| 206 | android_sdk_repository( |
| 207 | name = "androidsdk", |
| 208 | path = "/path/to/sdk", # or set ANDROID_HOME |
| 209 | ) |
| 210 | |
| 211 | # Android Test Support |
| 212 | ATS_COMMIT = "$COMMIT_HASH" |
| 213 | http_archive( |
| 214 | name = "android_test_support", |
Alex Humesky | 88a5891 | 2018-10-11 09:50:26 -0700 | [diff] [blame] | 215 | strip_prefix = "android-test-%s" % ATS_COMMIT, |
jingwen | c251ead | 2018-05-16 15:07:25 -0700 | [diff] [blame] | 216 | urls = ["https://github.com/android/android-test/archive/%s.tar.gz" % ATS_COMMIT], |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 217 | ) |
| 218 | load("@android_test_support//:repo.bzl", "android_test_repositories") |
| 219 | android_test_repositories() |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 220 | ``` |
| 221 | |
Googler | 1403a16 | 2021-01-22 13:42:50 -0800 | [diff] [blame] | 222 | ## Maven dependencies |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 223 | |
Googler | a1a29ec | 2021-02-26 12:19:25 -0800 | [diff] [blame] | 224 | For managing dependencies on Maven artifacts from repositories, such as [Google |
Jingwen Chen | 20b544a | 2019-03-21 12:52:28 -0700 | [diff] [blame] | 225 | Maven](https://maven.google.com) or [Maven Central](https://central.maven.org), |
Googler | a1a29ec | 2021-02-26 12:19:25 -0800 | [diff] [blame] | 226 | you should use a Maven resolver, such as |
Jingwen Chen | 20b544a | 2019-03-21 12:52:28 -0700 | [diff] [blame] | 227 | [rules_jvm_external](https://github.com/bazelbuild/rules_jvm_external). |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 228 | |
Googler | 47849d4 | 2021-01-15 17:43:25 -0800 | [diff] [blame] | 229 | The rest of this page shows how to use `rules_jvm_external` to |
Jingwen Chen | 20b544a | 2019-03-21 12:52:28 -0700 | [diff] [blame] | 230 | resolve and fetch dependencies from Maven repositories. |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 231 | |
Googler | 1403a16 | 2021-01-22 13:42:50 -0800 | [diff] [blame] | 232 | ## Choosing an android_device target |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 233 | |
| 234 | `android_instrumentation_test.target_device` specifies which Android device to |
| 235 | run the tests on. These `android_device` targets are defined in |
| 236 | [`@android_test_support`](https://github.com/google/android-testing-support-library/tree/master/tools/android/emulated_devices). |
| 237 | |
| 238 | ```python |
Googler | c38e667 | 2019-04-12 14:55:08 -0700 | [diff] [blame] | 239 | $ bazel query --output=build @android_test_support//tools/android/emulated_devices/generic_phone:android_23_x86 |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 240 | # .../external/android_test_support/tools/android/emulated_devices/generic_phone/BUILD:43:1 |
| 241 | android_device( |
Googler | c38e667 | 2019-04-12 14:55:08 -0700 | [diff] [blame] | 242 | name = "android_23_x86", |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 243 | visibility = ["//visibility:public"], |
| 244 | tags = ["requires-kvm"], |
| 245 | generator_name = "generic_phone", |
| 246 | generator_function = "make_device", |
| 247 | generator_location = "tools/android/emulated_devices/generic_phone/BUILD:43", |
| 248 | vertical_resolution = 800, |
| 249 | horizontal_resolution = 480, |
| 250 | ram = 2048, |
| 251 | screen_density = 240, |
| 252 | cache = 32, |
| 253 | vm_heap = 256, |
Googler | c38e667 | 2019-04-12 14:55:08 -0700 | [diff] [blame] | 254 | system_image = "@android_test_support//tools/android/emulated_devices/generic_phone:android_23_x86_images", |
| 255 | default_properties = "@android_test_support//tools/android/emulated_devices/generic_phone:_android_23_x86_props", |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 256 | ) |
| 257 | ``` |
| 258 | |
| 259 | The device target names use this template: |
| 260 | |
| 261 | ``` |
| 262 | @android_test_support//tools/android/emulated_devices/${device_type}:${system}_${api_level}_x86_qemu2 |
| 263 | ``` |
| 264 | |
| 265 | In order to launch an `android_device`, the `system_image` for the selected API |
| 266 | level is required. To download the system image, use Android SDK's |
| 267 | `tools/bin/sdkmanager`. For example, to download the system image for |
Googler | c38e667 | 2019-04-12 14:55:08 -0700 | [diff] [blame] | 268 | `generic_phone:android_23_x86`, run `$sdk/tools/bin/sdkmanager |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 269 | "system-images;android-23;default;x86"`. |
| 270 | |
| 271 | To see the full list of supported `android_device` targets in |
| 272 | `@android_test_support`, run the following command: |
| 273 | |
| 274 | ``` |
| 275 | bazel query 'filter("x86_qemu2$", kind(android_device, @android_test_support//tools/android/emulated_devices/...:*))' |
| 276 | ``` |
| 277 | |
Googler | a1a29ec | 2021-02-26 12:19:25 -0800 | [diff] [blame] | 278 | Bazel currently supports x86-based emulators only. For better performance, use |
| 279 | `QEMU2` `android_device` targets instead of `QEMU` ones. |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 280 | |
Googler | 1403a16 | 2021-01-22 13:42:50 -0800 | [diff] [blame] | 281 | ## Running tests |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 282 | |
jingwen | 7c70d82 | 2019-01-08 15:12:29 -0800 | [diff] [blame] | 283 | To run tests, add these lines to your project's `<project root>/.bazelrc` file. |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 284 | |
| 285 | ``` |
| 286 | # Configurations for testing with Bazel |
| 287 | # Select a configuration by running |
Marc Plano-Lesay | ae36130 | 2019-03-18 08:49:46 -0700 | [diff] [blame] | 288 | # `bazel test //my:target --config={headless, gui, local_device}` |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 289 | |
jingwen | 7c70d82 | 2019-01-08 15:12:29 -0800 | [diff] [blame] | 290 | # Headless instrumentation tests (No GUI) |
Marc Plano-Lesay | ae36130 | 2019-03-18 08:49:46 -0700 | [diff] [blame] | 291 | test:headless --test_arg=--enable_display=false |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 292 | |
| 293 | # Graphical instrumentation tests. Ensure that $DISPLAY is set. |
| 294 | test:gui --test_env=DISPLAY |
| 295 | test:gui --test_arg=--enable_display=true |
| 296 | |
| 297 | # Testing with a local emulator or device. Ensure that `adb devices` lists the |
| 298 | # device. |
| 299 | # Run tests serially. |
| 300 | test:local_device --test_strategy=exclusive |
| 301 | # Use the local device broker type, as opposed to WRAPPED_EMULATOR. |
| 302 | test:local_device --test_arg=--device_broker_type=LOCAL_ADB_SERVER |
| 303 | # Uncomment and set $device_id if there is more than one connected device. |
| 304 | # test:local_device --test_arg=--device_serial_number=$device_id |
| 305 | ``` |
| 306 | |
| 307 | Then, use one of the configurations to run tests: |
| 308 | |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 309 | - `bazel test //my/test:target --config=gui` |
Marc Plano-Lesay | ae36130 | 2019-03-18 08:49:46 -0700 | [diff] [blame] | 310 | - `bazel test //my/test:target --config=headless` |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 311 | - `bazel test //my/test:target --config=local_device` |
| 312 | |
| 313 | Use __only one configuration__ or tests will fail. |
| 314 | |
Googler | 1403a16 | 2021-01-22 13:42:50 -0800 | [diff] [blame] | 315 | ### Headless testing |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 316 | |
jingwen | b083de8 | 2018-04-30 07:53:09 -0700 | [diff] [blame] | 317 | With `Xvfb`, it is possible to test with emulators without the graphical |
| 318 | interface, also known as headless testing. To disable the graphical interface |
| 319 | when running tests, pass the test argument `--enable_display=false` to Bazel: |
| 320 | |
| 321 | ``` |
| 322 | bazel test //my/test:target --test_arg=--enable_display=false |
| 323 | ``` |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 324 | |
Googler | 1403a16 | 2021-01-22 13:42:50 -0800 | [diff] [blame] | 325 | ### GUI testing |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 326 | |
jingwen | b083de8 | 2018-04-30 07:53:09 -0700 | [diff] [blame] | 327 | If the `$DISPLAY` environment variable is set, it's possible to enable the |
| 328 | graphical interface of the emulator while the test is running. To do this, pass |
| 329 | these test arguments to Bazel: |
| 330 | |
| 331 | ``` |
Marc Plano-Lesay | 61a5fae | 2021-09-28 11:59:34 -0700 | [diff] [blame] | 332 | bazel test //my/test:target --test_arg=--enable_display=true --test_env=DISPLAY |
jingwen | b083de8 | 2018-04-30 07:53:09 -0700 | [diff] [blame] | 333 | ``` |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 334 | |
Googler | 1403a16 | 2021-01-22 13:42:50 -0800 | [diff] [blame] | 335 | ### Testing with a local emulator or device |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 336 | |
| 337 | Bazel also supports testing directly on a locally launched emulator or connected |
| 338 | device. Pass the flags |
| 339 | `--test_strategy=exclusive` and |
| 340 | `--test_arg=--device_broker_type=LOCAL_ADB_SERVER` to enable local testing mode. |
| 341 | If there is more than one connected device, pass the flag |
| 342 | `--test_arg=--device_serial_number=$device_id` where `$device_id` is the id of |
| 343 | the device/emulator listed in `adb devices`. |
| 344 | |
Googler | 1403a16 | 2021-01-22 13:42:50 -0800 | [diff] [blame] | 345 | ## Sample projects |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 346 | |
| 347 | If you are looking for canonical project samples, see the [Android testing |
| 348 | samples](https://github.com/googlesamples/android-testing#experimental-bazel-support) |
| 349 | for projects using Espresso and UIAutomator. |
| 350 | |
Googler | 1403a16 | 2021-01-22 13:42:50 -0800 | [diff] [blame] | 351 | ## Espresso setup |
jingwen | 8fe8018 | 2018-10-01 09:05:05 -0700 | [diff] [blame] | 352 | |
| 353 | If you write UI tests with [Espresso](https://developer.android.com/training/testing/espresso/) |
| 354 | (`androidx.test.espresso`), you can use the following snippets to set up your |
| 355 | Bazel workspace with the list of commonly used Espresso artifacts and their |
| 356 | dependencies: |
| 357 | |
| 358 | ``` |
| 359 | androidx.test.espresso:espresso-core |
| 360 | androidx.test:rules |
| 361 | androidx.test:runner |
| 362 | javax.inject:javax.inject |
| 363 | org.hamcrest:java-hamcrest |
| 364 | junit:junit |
| 365 | ``` |
| 366 | |
| 367 | One way to organize these dependencies is to create a `//:test_deps` shared |
| 368 | library: |
| 369 | |
| 370 | ```python |
| 371 | # In <project root>/BUILD.bazel |
| 372 | |
jingwen | 8fe8018 | 2018-10-01 09:05:05 -0700 | [diff] [blame] | 373 | java_library( |
| 374 | name = "test_deps", |
| 375 | visibility = ["//visibility:public"], |
| 376 | exports = [ |
Jingwen Chen | 20b544a | 2019-03-21 12:52:28 -0700 | [diff] [blame] | 377 | "@maven//:androidx_test_espresso_espresso_core", |
| 378 | "@maven//:androidx_test_rules", |
| 379 | "@maven//:androidx_test_runner", |
| 380 | "@maven//:javax_inject_javax_inject" |
| 381 | "@maven//:org_hamcrest_java_hamcrest", |
| 382 | "@maven//:junit_junit", |
jingwen | 8fe8018 | 2018-10-01 09:05:05 -0700 | [diff] [blame] | 383 | ], |
| 384 | ) |
| 385 | ``` |
| 386 | |
| 387 | Then, add the required dependencies in `<project root>/WORKSPACE`: |
| 388 | |
| 389 | |
| 390 | ```python |
Jingwen Chen | 20b544a | 2019-03-21 12:52:28 -0700 | [diff] [blame] | 391 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") |
jingwen | 8fe8018 | 2018-10-01 09:05:05 -0700 | [diff] [blame] | 392 | |
jingwen | ae7629a | 2019-10-17 10:18:40 -0700 | [diff] [blame] | 393 | RULES_JVM_EXTERNAL_TAG = "2.8" |
| 394 | RULES_JVM_EXTERNAL_SHA = "79c9850690d7614ecdb72d68394f994fef7534b292c4867ce5e7dec0aa7bdfad" |
jingwen | 8fe8018 | 2018-10-01 09:05:05 -0700 | [diff] [blame] | 395 | |
| 396 | http_archive( |
Jingwen Chen | 20b544a | 2019-03-21 12:52:28 -0700 | [diff] [blame] | 397 | name = "rules_jvm_external", |
| 398 | strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG, |
| 399 | sha256 = RULES_JVM_EXTERNAL_SHA, |
| 400 | url = "https://github.com/bazelbuild/rules_jvm_external/archive/%s.zip" % RULES_JVM_EXTERNAL_TAG, |
jingwen | 8fe8018 | 2018-10-01 09:05:05 -0700 | [diff] [blame] | 401 | ) |
| 402 | |
Jingwen Chen | 20b544a | 2019-03-21 12:52:28 -0700 | [diff] [blame] | 403 | load("@rules_jvm_external//:defs.bzl", "maven_install") |
jingwen | 8fe8018 | 2018-10-01 09:05:05 -0700 | [diff] [blame] | 404 | |
Jingwen Chen | 20b544a | 2019-03-21 12:52:28 -0700 | [diff] [blame] | 405 | maven_install( |
| 406 | artifacts = [ |
| 407 | "junit:junit:4.12", |
| 408 | "javax.inject:javax.inject:1", |
| 409 | "org.hamcrest:java-hamcrest:2.0.0.0" |
| 410 | "androidx.test.espresso:espresso-core:3.1.1", |
| 411 | "androidx.test:rules:aar:1.1.1", |
| 412 | "androidx.test:runner:aar:1.1.1", |
| 413 | ], |
| 414 | repositories = [ |
| 415 | "https://maven.google.com", |
| 416 | "https://repo1.maven.org/maven2", |
| 417 | ], |
jingwen | 8fe8018 | 2018-10-01 09:05:05 -0700 | [diff] [blame] | 418 | ) |
| 419 | ``` |
| 420 | |
| 421 | Finally, in your test `android_binary` target, add the `//:test_deps` |
| 422 | dependency: |
| 423 | |
| 424 | ```python |
| 425 | android_binary( |
| 426 | name = "my_test_app", |
| 427 | instruments = "//path/to:app", |
| 428 | deps = [ |
| 429 | "//:test_deps", |
| 430 | # ... |
| 431 | ], |
| 432 | # ... |
| 433 | ) |
| 434 | ``` |
| 435 | |
Googler | 1403a16 | 2021-01-22 13:42:50 -0800 | [diff] [blame] | 436 | ## Tips |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 437 | |
Googler | 1403a16 | 2021-01-22 13:42:50 -0800 | [diff] [blame] | 438 | ### Reading test logs |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 439 | |
| 440 | Use `--test_output=errors` to print logs for failing tests, or |
| 441 | `--test_output=all` to print all test output. If you're looking for an |
| 442 | individual test log, go to |
| 443 | `$PROJECT_ROOT/bazel-testlogs/path/to/InstrumentationTestTargetName`. |
| 444 | |
| 445 | For example, the test logs for `BasicSample` canonical project are in |
| 446 | `bazel-testlogs/ui/espresso/BasicSample/BasicSampleInstrumentationTest`: |
| 447 | |
| 448 | ``` |
| 449 | $ tree bazel-testlogs/ui/espresso/BasicSample/BasicSampleInstrumentationTest |
| 450 | . |
| 451 | ├── adb.409923.log |
| 452 | ├── broker_logs |
| 453 | │ ├── aapt_binary.10.ok.txt |
| 454 | │ ├── aapt_binary.11.ok.txt |
| 455 | │ ├── adb.12.ok.txt |
| 456 | │ ├── adb.13.ok.txt |
| 457 | │ ├── adb.14.ok.txt |
| 458 | │ ├── adb.15.fail.txt |
| 459 | │ ├── adb.16.ok.txt |
| 460 | │ ├── adb.17.fail.txt |
| 461 | │ ├── adb.18.ok.txt |
| 462 | │ ├── adb.19.fail.txt |
| 463 | │ ├── adb.20.ok.txt |
| 464 | │ ├── adb.21.ok.txt |
| 465 | │ ├── adb.22.ok.txt |
| 466 | │ ├── adb.23.ok.txt |
| 467 | │ ├── adb.24.fail.txt |
| 468 | │ ├── adb.25.ok.txt |
| 469 | │ ├── adb.26.fail.txt |
| 470 | │ ├── adb.27.ok.txt |
| 471 | │ ├── adb.28.fail.txt |
| 472 | │ ├── adb.29.ok.txt |
| 473 | │ ├── adb.2.ok.txt |
| 474 | │ ├── adb.30.ok.txt |
| 475 | │ ├── adb.3.ok.txt |
| 476 | │ ├── adb.4.ok.txt |
| 477 | │ ├── adb.5.ok.txt |
| 478 | │ ├── adb.6.ok.txt |
| 479 | │ ├── adb.7.ok.txt |
| 480 | │ ├── adb.8.ok.txt |
| 481 | │ ├── adb.9.ok.txt |
Googler | c38e667 | 2019-04-12 14:55:08 -0700 | [diff] [blame] | 482 | │ ├── android_23_x86.1.ok.txt |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 483 | │ └── exec-1 |
| 484 | │ ├── adb-2.txt |
| 485 | │ ├── emulator-2.txt |
| 486 | │ └── mksdcard-1.txt |
| 487 | ├── device_logcat |
| 488 | │ └── logcat1635880625641751077.txt |
| 489 | ├── emulator_itCqtc.log |
| 490 | ├── outputs.zip |
| 491 | ├── pipe.log.txt |
| 492 | ├── telnet_pipe.log.txt |
| 493 | └── tmpuRh4cy |
| 494 | ├── watchdog.err |
| 495 | └── watchdog.out |
| 496 | |
| 497 | 4 directories, 41 files |
| 498 | ``` |
| 499 | |
Googler | 1403a16 | 2021-01-22 13:42:50 -0800 | [diff] [blame] | 500 | ### Reading emulator logs |
jingwen | b083de8 | 2018-04-30 07:53:09 -0700 | [diff] [blame] | 501 | |
| 502 | The emulator logs for `android_device` targets are stored in the `/tmp/` |
| 503 | directory with the name `emulator_xxxxx.log`, where `xxxxx` is a |
| 504 | randomly-generated sequence of characters. |
| 505 | |
| 506 | Use this command to find the latest emulator log: |
| 507 | |
| 508 | ``` |
| 509 | ls -1t /tmp/emulator_*.log | head -n 1 |
| 510 | ``` |
| 511 | |
Googler | 1403a16 | 2021-01-22 13:42:50 -0800 | [diff] [blame] | 512 | ### Testing against multiple API levels |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 513 | |
| 514 | If you would like to test against multiple API levels, you can use a list |
| 515 | comprehension to create test targets for each API level. For example: |
| 516 | |
| 517 | ```python |
| 518 | API_LEVELS = [ |
| 519 | "19", |
| 520 | "20", |
| 521 | "21", |
| 522 | "22", |
| 523 | ] |
| 524 | |
| 525 | [android_instrumentation_test( |
| 526 | name = "my_test_%s" % API_LEVEL, |
| 527 | test_app = ":my_test_app", |
| 528 | target_device = "@android_test_support//tools/android/emulated_devices/generic_phone:android_%s_x86_qemu2" % API_LEVEL, |
| 529 | ) for API_LEVEL in API_LEVELS] |
| 530 | ``` |
| 531 | |
Googler | 1403a16 | 2021-01-22 13:42:50 -0800 | [diff] [blame] | 532 | ## Known issues |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 533 | |
| 534 | - [Forked adb server processes are not terminated after |
| 535 | tests](https://github.com/bazelbuild/bazel/issues/4853) |
jingwen | 2f96327 | 2018-04-11 20:18:44 -0700 | [diff] [blame] | 536 | - While APK building works on all platforms (Linux, macOS, Windows), testing |
| 537 | only works on Linux. |
| 538 | - Even with `--config=local_adb`, users still need to specify |
| 539 | `android_instrumentation_test.target_device`. |
| 540 | - If using a local device or emulator, Bazel does not uninstall the APKs after |
| 541 | the test. Clean the packages by running this command: `adb shell pm list |
| 542 | packages com.example.android.testing | cut -d ':' -f 2 | tr -d '\r' | xargs |
| 543 | -L1 -t adb uninstall` |