jbudorick | 5a9b37f5 | 2016-08-17 00:36:43 | [diff] [blame] | 1 | # Android Instrumentation Tests |
| 2 | |
| 3 | Instrumentation tests are Java tests based on |
| 4 | [`android.app.Instrumentation`](https://developer.android.com/reference/android/app/Instrumentation.html). |
| 5 | They run on a device. |
| 6 | |
| 7 | [TOC] |
| 8 | |
| 9 | ## Writing an instrumentation test |
| 10 | |
| 11 | Currently, an instrumentation test is just a JUnit3-style test based on |
| 12 | [android.test.InstrumentationTestCase](https://developer.android.com/reference/android/test/InstrumentationTestCase.html). |
| 13 | (This will change starting in [Android N](https://en.wikipedia.org/wiki/Android_Nougat).) |
| 14 | |
| 15 | Writing an instrumentation test case can be simple, e.g. |
| 16 | |
| 17 | ```java |
| 18 | package org.chromium.sample.test; |
| 19 | |
| 20 | import android.test.InstrumentationTestCase; |
| 21 | |
| 22 | public class MyInstrumentationTest extends InstrumentationTestCase { |
| 23 | |
| 24 | // Note that, because it's a JUnit3-style test, the test method *must* |
| 25 | // start with "test". |
| 26 | public void testTheFirst() { |
| 27 | bool writingInstrumentationTestsCanBeEasy = true; |
| 28 | |
| 29 | // InstrumentationTestCase inherits the assert* methods through |
| 30 | // junit.framework.TestCase. |
| 31 | assertTrue(writingInstrumentationTestsCanBeEasy); |
| 32 | } |
| 33 | |
| 34 | public void testTheSecond() { |
| 35 | bool writingInstrumentationTestsIsAlwaysEasy = false; |
| 36 | assertFalse(writingInstrumentationTestsIsAlwaysEasy); |
| 37 | } |
| 38 | } |
| 39 | ``` |
| 40 | |
| 41 | After writing a test, you can run it by: |
| 42 | |
| 43 | - Adding the file to the relevant gn target if the entire file is new. |
| 44 | Typically, the "relevant gn target" is simply the target containing the |
| 45 | other files in the same directory. |
| 46 | - Rebuild. |
| 47 | - Run the test using the process described [here](/testing/android/docs/todo.md). |
| 48 | |
| 49 | ## Instrumentation test features |
| 50 | |
| 51 | In many cases, Chromium has extended the instrumentation test framework |
| 52 | classes to implement additional features. |
| 53 | |
Nick Ward | c650fdf | 2017-08-12 01:13:42 | [diff] [blame] | 54 | ### Tracing |
jbudorick | 5a9b37f5 | 2016-08-17 00:36:43 | [diff] [blame] | 55 | |
Nick Ward | c650fdf | 2017-08-12 01:13:42 | [diff] [blame] | 56 | Enabling tracing during a test run allows all the function calls involved to be |
| 57 | observed in a visual display (using Chrome's built-in chrome://tracing feature). |
| 58 | To run a test with tracing, add the `--trace-output` flag to the command used to |
| 59 | call the instrumentation test (either running the test_runner.py script, or a |
| 60 | generated binary such as `run_chrome_public_test_apk`). The `--trace-output` flag |
| 61 | takes a filename, which, after the test run, will contain a JSON file readable |
| 62 | by chrome://tracing. |
jbudorick | 5a9b37f5 | 2016-08-17 00:36:43 | [diff] [blame] | 63 | |
Nick Ward | c650fdf | 2017-08-12 01:13:42 | [diff] [blame] | 64 | By default, the trace includes only certain function calls important to the test |
| 65 | run, both within the Python test runner framework and the Java code running on |
| 66 | the device. For a more detailed look, add the (no-argument) `--trace-all` flag. |
| 67 | This causes every function called on the Python side to be added to the trace. |
jbudorick | 5a9b37f5 | 2016-08-17 00:36:43 | [diff] [blame] | 68 | |
| 69 | ### Annotations |
| 70 | |
| 71 | Instrumentation tests in Chromium use a wide variety of annotations to control |
| 72 | and manipulate test execution. Some of these are implemented in Chromium, while |
| 73 | others are pulled in from outside. They include: |
| 74 | |
Michael Thiessen | 6bafbf0 | 2020-05-25 20:49:35 | [diff] [blame] | 75 | #### Test Batching |
| 76 | |
John Palmer | a8515fca | 2021-05-20 03:35:32 | [diff] [blame^] | 77 | The [`@Batch("group_name")`](https://chromium.googlesource.com/chromium/src/+/main/base/test/android/javatests/src/org/chromium/base/test/util/Batch.java) |
Michael Thiessen | 6bafbf0 | 2020-05-25 20:49:35 | [diff] [blame] | 78 | annotation is used to run all tests with the same batch group name in the same |
| 79 | instrumentation invocation. In other words, the browser process is not |
| 80 | restarted between these tests, and so any changes to global state, like |
| 81 | launching an Activity, will persist between tests within a batch group. The |
| 82 | benefit of this is that these tests run significantly faster - the per-test cost |
| 83 | of restarting the process can be as high as 10 seconds (usually around 2 |
| 84 | seconds), and that doesn't count the cost of starting an Activity like |
| 85 | ChromeTabbedActivity. |
| 86 | |
jbudorick | 5a9b37f5 | 2016-08-17 00:36:43 | [diff] [blame] | 87 | #### Size annotations |
| 88 | |
| 89 | Size annotations are used primarily by the test runner to determine the length |
| 90 | of time to wait before considering a test hung (i.e., its timeout duration). |
| 91 | |
| 92 | Several of the annotations are Android APIs from |
| 93 | [android.test.suitebuilder.annotation](https://developer.android.com/reference/android/test/suitebuilder/annotation/package-summary.html) |
| 94 | (prior to [Android N](https://en.wikipedia.org/wiki/Android_Nougat)) or |
| 95 | [android.support.test.filters](https://developer.android.com/reference/android/support/test/filters/package-summary.html) |
| 96 | (starting in Android N). These are all fairly self-explanatory: |
| 97 | |
Michael Thiessen | 4dd7278c | 2021-03-22 16:46:32 | [diff] [blame] | 98 | - [`@SmallTest`](https://developer.android.com/reference/android/support/test/filters/SmallTest.html) (timeout: **10 seconds**) |
| 99 | - [`@MediumTest`](https://developer.android.com/reference/android/support/test/filters/MediumTest.html) (timeout: **30 seconds**) |
| 100 | - [`@LargeTest`](https://developer.android.com/reference/android/support/test/filters/LargeTest.html) (timeout: **2 minutes**) |
jbudorick | 5a9b37f5 | 2016-08-17 00:36:43 | [diff] [blame] | 101 | |
| 102 | A few additional size annotations are provided in |
John Palmer | a8515fca | 2021-05-20 03:35:32 | [diff] [blame^] | 103 | [//base](https://chromium.googlesource.com/chromium/src/+/main/base): |
jbudorick | 5a9b37f5 | 2016-08-17 00:36:43 | [diff] [blame] | 104 | |
John Palmer | a8515fca | 2021-05-20 03:35:32 | [diff] [blame^] | 105 | - [`@EnormousTest`](https://chromium.googlesource.com/chromium/src/+/main/base/test/android/javatests/src/org/chromium/base/test/util/EnormousTest.java) |
Michael Thiessen | 4dd7278c | 2021-03-22 16:46:32 | [diff] [blame] | 106 | (timeout: **5 minutes**) Typically used for tests that require WiFi. |
John Palmer | a8515fca | 2021-05-20 03:35:32 | [diff] [blame^] | 107 | - [`@IntegrationTest`](https://chromium.googlesource.com/chromium/src/+/main/base/test/android/javatests/src/org/chromium/base/test/util/IntegrationTest.java) |
Michael Thiessen | 4dd7278c | 2021-03-22 16:46:32 | [diff] [blame] | 108 | (timeout: **10 minutes**) Used for tests that run against real services. |
John Palmer | a8515fca | 2021-05-20 03:35:32 | [diff] [blame^] | 109 | - [`@Manual`](https://chromium.googlesource.com/chromium/src/+/main/base/test/android/javatests/src/org/chromium/base/test/util/Manual.java) |
jbudorick | 5a9b37f5 | 2016-08-17 00:36:43 | [diff] [blame] | 110 | (timeout: **10 hours**) Used for manual tests. |
| 111 | |
| 112 | Beware that the timeout durations for these annotations are subject to |
| 113 | change, though they rarely do. These values are defined |
John Palmer | a8515fca | 2021-05-20 03:35:32 | [diff] [blame^] | 114 | [here](https://chromium.googlesource.com/chromium/src/+/main/build/android/pylib/local/device/local_device_instrumentation_test_run.py#20). |
jbudorick | 5a9b37f5 | 2016-08-17 00:36:43 | [diff] [blame] | 115 | |
| 116 | #### Annotations that disable tests |
| 117 | |
| 118 | There are several annotations that control whether or not a test runs. |
| 119 | Some are conditional, others are not. |
| 120 | |
| 121 | ##### Unconditional disabling |
| 122 | |
John Palmer | a8515fca | 2021-05-20 03:35:32 | [diff] [blame^] | 123 | [**@DisabledTest**](https://chromium.googlesource.com/chromium/src/+/main/base/test/android/javatests/src/org/chromium/base/test/util/DisabledTest.java) |
jbudorick | a2d64d1 | 2016-08-22 22:10:00 | [diff] [blame] | 124 | unconditionally disables a test. |
| 125 | ```java |
| 126 | @DisabledTest( |
| 127 | // Describes why the test is disabled. Typically includes a crbug link. |
| 128 | message = "" |
| 129 | ) |
| 130 | ``` |
jbudorick | 5a9b37f5 | 2016-08-17 00:36:43 | [diff] [blame] | 131 | |
John Palmer | a8515fca | 2021-05-20 03:35:32 | [diff] [blame^] | 132 | [**@FlakyTest**](https://chromium.googlesource.com/chromium/src/+/main/base/test/android/javatests/src/org/chromium/base/test/util/FlakyTest.java) |
jbudorick | a2d64d1 | 2016-08-22 22:10:00 | [diff] [blame] | 133 | marks a test as flaky. This also unconditionally disables the test, though |
| 134 | tests marked with **@FlakyTest** are explicitly run on some bots. |
| 135 | ```java |
| 136 | @FlakyTest( |
| 137 | // Describes why the test is marked flaky. Typically includes a crbug link. |
| 138 | message = "" |
| 139 | ) |
| 140 | ``` |
jbudorick | 5a9b37f5 | 2016-08-17 00:36:43 | [diff] [blame] | 141 | |
jbudorick | a2d64d1 | 2016-08-22 22:10:00 | [diff] [blame] | 142 | Note that there are Android versions of **@DisabledTest** and **@FlakyTest** |
| 143 | that do not allow message specification. These are no longer used in Chromium. |
| 144 | |
| 145 | As alluded to above, tests marked with either **@DisabledTest** or |
| 146 | **@FlakyTest** can be explicitly run via the test runner's |
| 147 | [-A/--annotation](/testing/android/docs/todo.md) |
| 148 | flag. For example, this would run only the tests marked as flaky in |
| 149 | `chrome_public_test_apk`: |
| 150 | |
| 151 | ```bash |
| 152 | ./out/Debug/bin/run_chrome_public_test_apk -A FlakyTest |
| 153 | ``` |
jbudorick | 5a9b37f5 | 2016-08-17 00:36:43 | [diff] [blame] | 154 | |
| 155 | ##### Conditional disabling |
| 156 | |
| 157 | There are two primary annotation categories that conditionally disable tests: |
| 158 | **@DisableIf** and **@Restriction**. The **@DisableIf** annotations are intended |
| 159 | to temporarily disable a test in certain scenarios where it *should* work but |
| 160 | doesn't. In contrast, the **@Restriction** annotation is intended to |
| 161 | permanently limit a test to specific configurations. It signifies that the test |
| 162 | was not, is not, and will not be intended to run beyond those configurations. |
| 163 | In both cases, conditional disabling manifests as a skipped test. |
| 164 | |
John Palmer | a8515fca | 2021-05-20 03:35:32 | [diff] [blame^] | 165 | [**@DisableIf.Build**](https://chromium.googlesource.com/chromium/src/+/main/base/test/android/javatests/src/org/chromium/base/test/util/DisableIf.java#25) |
jbudorick | a2d64d1 | 2016-08-22 22:10:00 | [diff] [blame] | 166 | allows for conditional test disabling based on values in |
jbudorick | 5a9b37f5 | 2016-08-17 00:36:43 | [diff] [blame] | 167 | [`android.os.Build`](https://developer.android.com/reference/android/os/Build.html): |
| 168 | |
| 169 | ```java |
| 170 | @DisableIf.Build( |
| 171 | |
| 172 | // Describes why the test is disabled. |
| 173 | message = "", |
| 174 | |
| 175 | // Disables the test on SDK levels that match the given conditions. |
| 176 | // Checks against Build.VERSION.SDK_INT. |
| 177 | sdk_is_greater_than = 0, |
| 178 | sdk_is_less_than = Integer.MAX_VALUE, |
| 179 | |
| 180 | // Disables the test on devices that support the given ABI |
| 181 | // (e.g. "arm64-v8a"). Checks against: |
| 182 | // - Build.SUPPORTED_ABIS on L+ |
| 183 | // - Build.CPU_ABI and Build.CPU_ABI2 otherwise |
| 184 | supported_abis_includes = "", |
| 185 | |
| 186 | // Disables the test on devices with hardware that matches the given |
| 187 | // value. Checks against Build.HARDWARE. |
| 188 | hardware_is = "", |
| 189 | |
| 190 | // Disables the test on devices with product names that contain the |
| 191 | // given value. Checks against Build.PRODUCT. |
| 192 | product_name_includes = "", |
| 193 | |
| 194 | ) |
| 195 | ``` |
| 196 | |
John Palmer | a8515fca | 2021-05-20 03:35:32 | [diff] [blame^] | 197 | [**@DisableIf.Device**](https://chromium.googlesource.com/chromium/src/+/main/base/test/android/javatests/src/org/chromium/base/test/util/DisableIf.java#40) |
jbudorick | a2d64d1 | 2016-08-22 22:10:00 | [diff] [blame] | 198 | allows for conditional test disabling based on whether |
jbudorick | 5a9b37f5 | 2016-08-17 00:36:43 | [diff] [blame] | 199 | a device is a phone, a tablet, or a "large tablet" as determined by |
John Palmer | a8515fca | 2021-05-20 03:35:32 | [diff] [blame^] | 200 | [org.chromium.ui.base.DeviceFormFactor](https://chromium.googlesource.com/chromium/src/+/main/ui/android/java/src/org/chromium/ui/base/DeviceFormFactor.java). |
Shenghua Zhang | cac866d | 2017-08-29 01:30:55 | [diff] [blame] | 201 | This is available to tests in |
John Palmer | a8515fca | 2021-05-20 03:35:32 | [diff] [blame^] | 202 | [//ui](https://chromium.googlesource.com/chromium/src/+/main/ui/) |
Shenghua Zhang | cac866d | 2017-08-29 01:30:55 | [diff] [blame] | 203 | or code that uses //ui. |
jbudorick | 5a9b37f5 | 2016-08-17 00:36:43 | [diff] [blame] | 204 | |
| 205 | ```java |
| 206 | @DisableIf.Device( |
| 207 | // Disables the test on devices that match the given type(s) as described |
| 208 | // above. |
| 209 | type = {} |
| 210 | ) |
| 211 | ``` |
| 212 | |
John Palmer | a8515fca | 2021-05-20 03:35:32 | [diff] [blame^] | 213 | [**@Restriction**](https://chromium.googlesource.com/chromium/src/+/main/base/test/android/javatests/src/org/chromium/base/test/util/Restriction.java) |
jbudorick | a2d64d1 | 2016-08-22 22:10:00 | [diff] [blame] | 214 | currently allows for conditional test disabling based on device |
jbudorick | 5a9b37f5 | 2016-08-17 00:36:43 | [diff] [blame] | 215 | type, device performance, internet connectivity, whether Google Play Services is |
| 216 | up to date, and whether the build was an official one. |
| 217 | |
| 218 | ```java |
| 219 | @Restriction( |
| 220 | // Possible values include: |
| 221 | // |
Michael Thiessen | 6bafbf0 | 2020-05-25 20:49:35 | [diff] [blame] | 222 | // base: |
jbudorick | 5a9b37f5 | 2016-08-17 00:36:43 | [diff] [blame] | 223 | // - Restriction.RESTRICTION_TYPE_LOW_END_DEVICE |
| 224 | // Restricts the test to low-end devices as determined by SysUtils.isLowEndDevice(). |
| 225 | // |
| 226 | // - Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE |
| 227 | // Restricts the test to non-low-end devices as determined by SysUtils.isLowEndDevice(). |
| 228 | // |
| 229 | // - Restriction.RESTRICTION_TYPE_INTERNET |
| 230 | // Restricts the test to devices that have an internet connection. |
| 231 | // |
| 232 | // chrome: |
| 233 | // - ChromeRestriction.RESTRICTION_TYPE_GOOGLE_PLAY_SERVICES |
| 234 | // Restricts the test to devices with up-to-date versions of Google Play Services. |
| 235 | // |
jbudorick | 5a9b37f5 | 2016-08-17 00:36:43 | [diff] [blame] | 236 | // - ChromeRestriction.RESTRICTION_TYPE_OFFICIAL_BUILD |
| 237 | // Restricts the test to official builds as determined by ChromeVersionInfo.isOfficialBuild(). |
Shenghua Zhang | cac866d | 2017-08-29 01:30:55 | [diff] [blame] | 238 | // |
| 239 | // ui: |
| 240 | // - UiRestriction.RESTRICTION_TYPE_PHONE |
| 241 | // Restricts the test to phones as determined by DeviceFormFactor. |
| 242 | // |
| 243 | // - UiRestriction.RESTRICTION_TYPE_TABLET |
| 244 | // Restricts the test to tablets as determined by DeviceFormFactor. |
jbudorick | 5a9b37f5 | 2016-08-17 00:36:43 | [diff] [blame] | 245 | value = {} |
| 246 | ) |
| 247 | ``` |
| 248 | |
John Palmer | a8515fca | 2021-05-20 03:35:32 | [diff] [blame^] | 249 | [**@MinAndroidSdkLevel**](https://chromium.googlesource.com/chromium/src/+/main/base/test/android/javatests/src/org/chromium/base/test/util/MinAndroidSdkLevel.java) |
jbudorick | a2d64d1 | 2016-08-22 22:10:00 | [diff] [blame] | 250 | is similar to **@Restriction** in purpose in that it's |
jbudorick | 5a9b37f5 | 2016-08-17 00:36:43 | [diff] [blame] | 251 | intended to permanently limit a test to only recent versions of Android. |
| 252 | |
| 253 | ```java |
| 254 | @MinAndroidSdkLevel( |
| 255 | // The minimum SDK level at which this test should be executed. Checks |
| 256 | // against Build.VERSION.SDK_INT. |
| 257 | value = 0 |
| 258 | ) |
| 259 | ``` |
| 260 | |
| 261 | #### Annotations that affect how a test is run |
| 262 | |
| 263 | Several annotations affect how a test is run in interesting or nontrivial ways. |
| 264 | |
John Palmer | a8515fca | 2021-05-20 03:35:32 | [diff] [blame^] | 265 | [**@CommandLineFlags.Add**](https://chromium.googlesource.com/chromium/src/+/main/base/test/android/javatests/src/org/chromium/base/test/util/CommandLineFlags.java#46) |
jbudorick | a2d64d1 | 2016-08-22 22:10:00 | [diff] [blame] | 266 | and |
John Palmer | a8515fca | 2021-05-20 03:35:32 | [diff] [blame^] | 267 | [**@CommandLineFlags.Remove**](https://chromium.googlesource.com/chromium/src/+/main/base/test/android/javatests/src/org/chromium/base/test/util/CommandLineFlags.java#58) |
jbudorick | a2d64d1 | 2016-08-22 22:10:00 | [diff] [blame] | 268 | manipulate Chrome's |
jbudorick | 5a9b37f5 | 2016-08-17 00:36:43 | [diff] [blame] | 269 | command-line flags on a per-test basis (i.e., the flags handled by |
John Palmer | a8515fca | 2021-05-20 03:35:32 | [diff] [blame^] | 270 | [`org.chromium.base.CommandLine`](https://chromium.googlesource.com/chromium/src/+/main/base/android/java/src/org/chromium/base/CommandLine.java) and |
| 271 | [`base::CommandLine`](https://chromium.googlesource.com/chromium/src/+/main/base/command_line.h)). |
jbudorick | 5a9b37f5 | 2016-08-17 00:36:43 | [diff] [blame] | 272 | |
| 273 | ```java |
| 274 | @CommandLineFlags.Add( |
| 275 | // The flags to add to the command line for this test. These can be |
| 276 | // anything and typically should include the leading dashes (e.g. "--foo"). |
| 277 | value = {} |
| 278 | ) |
| 279 | |
| 280 | @CommandLineFlags.Remove( |
| 281 | // The flags to remove from the command line for this test. These can only |
| 282 | // be flags added via @CommandLineFlags.Add. Flags already present in the |
| 283 | // command-line file on the device are only present in the native |
| 284 | // CommandLine object and cannot be manipulated. |
| 285 | value = {} |
| 286 | ) |
| 287 | ``` |
| 288 | |
| 289 | #### Feature annotations |
| 290 | |
John Palmer | a8515fca | 2021-05-20 03:35:32 | [diff] [blame^] | 291 | [**@Feature**](https://chromium.googlesource.com/chromium/src/+/main/base/test/android/javatests/src/org/chromium/base/test/util/Feature.java) |
jbudorick | a2d64d1 | 2016-08-22 22:10:00 | [diff] [blame] | 292 | has been used inconsistently in Chromium to group tests across |
jbudorick | 5a9b37f5 | 2016-08-17 00:36:43 | [diff] [blame] | 293 | test cases according to the feature they're testing. |
| 294 | |
| 295 | ```java |
| 296 | @Feature( |
| 297 | // The features associated with this test. These can be anything. |
| 298 | value = {} |
| 299 | ) |
| 300 | ``` |
| 301 | |
| 302 | @Feature doesn't have an inherent function, but it can be used to filter tests |
| 303 | via the test runner's |
| 304 | [-A/--annotation](/testing/android/docs/todo.md) and |
| 305 | [-E/--exclude-annotation](/testing/android/docs/todo.md) flags. For example, |
| 306 | this would run only the tests with @Feature annotations containing at least |
| 307 | "Sync" in `chrome_public_test_apk`: |
| 308 | |
| 309 | ```bash |
| 310 | out/Debug/bin/run_chrome_public_test_apk -A Feature=Sync |
| 311 | ``` |
jbudorick | 2d4f2689 | 2017-01-09 16:51:06 | [diff] [blame] | 312 | |
| 313 | ## Advanced |
| 314 | |
| 315 | - [Creating a component for use in instrumentation tests.](/testing/android/docs/components_for_testing.md) |