1# Testing 2 3[TOC] 4 5AndroidX contains unit and integration tests that are run automatically when a 6change is uploaded. It also contains a number of sample applications that are 7useful for demonstrating how to use features as well as performing manual 8testing. 9 10## Motivation 11 12Jetpack libraries are developed with the intention that they are functionally 13stable and production-ready as of the first public `alpha01` release, and that 14they remain production-ready at tip-of-tree thereafter. 15 16For this reason, we emphasize that continuous integration testing -- both pre- 17and post-submit -- is the ultimate source of truth for library correctness. If 18tests are failing at head, the library is not only at risk of blocking public 19releases but at risk of breaking production Google apps that rely on its 20tip-of-tree builds. 21 22### API level coverage in CI 23 24Generally, we aim to test Jetpack libraries against (1) the earliest supported 25API level, (2) the latest stable API level, (3) API levels with major changes, 26(4) API levels with high concentration of devices in the field, and (5) the next 27pre-release API level. 28 29In practice, this is limited by device and emulator availability and 30reliability. As of January 2025, we run tests on the following API levels: 31 32- API level 21: the lowest API level supported by Firebase Test Lab (FTL) 33- API level 26: the lowest supported ARM-based emulator FTL runner, which has 34 much greater performance and stability 35- API levels 30, 33, 34, 35: the latest supported API levels, which represent 36 the majority of devices in the field 37 38## Adding tests {#adding} 39 40For an example of how to set up simple unit and integration tests in a new 41module, see 42[aosp/1189799](https://android-review.googlesource.com/c/platform/frameworks/support/+/1189799). 43For an example of how to set up Espresso-powered integration tests, see the 44`preference` library's 45[`build.gradle`](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:preference/preference/build.gradle) 46and 47[`EditTextPreferenceTest.java`](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:preference/preference/src/androidTest/java/androidx/preference/tests/EditTextPreferenceTest.java) 48files. 49 50The currently allowed test runners for on-device tests are 51[`AndroidJUnitRunner`](https://developer.android.com/training/testing/junit-runner) 52and 53[`Parameterized`](https://junit.org/junit4/javadoc/4.12/org/junit/runners/Parameterized.html). 54 55NOTE All package/class/method combinations must be unique. Multiple copies of 56the same class/method can be included e.g. under different directories, but must 57be distinguishable by their packages. 58 59NOTE For best practices on writing libraries in a way that makes it easy for end 60users -- and library developers -- to write tests, see the 61[Testability](/docs/testability.md) guide. 62 63### Adding screenshots tests using scuba library 64 65#### Prerequisites 66 67Golden project: Make sure that you have the golden directory in your root 68checkout (sibling of frameworks directory). If not re-init your repo to fetch 69the latest manifest file: 70 71``` 72$ repo init -u sso://android/platform/manifest \ 73 -b androidx-main && repo sync -c -j8 74``` 75 76Set up your module: If your module is not using screenshot tests yet, you need 77to do the initial setup. 78 791. Modify your gradle file: Add dependency on the diffing library into your 80 gradle file: 81 82 ``` 83 androidTestImplementation project(“:test:screenshot:screenshot”) 84 ``` 85 86 Important step: Add golden asset directory to be linked to your test apk: 87 88 ``` 89 android { 90 sourceSets.androidTest.assets.srcDirs += 91 // For androidx project (not in ui dir) use "/../../golden/project" 92 project.rootDir.absolutePath + "/../../golden/compose/material/material" 93 } 94 ``` 95 96 This will bundle the goldens into your apk so they can be retrieved during 97 the test. 98 992. Create directory and variable: In the golden directory, create a new 100 directory for your module (the directory that you added to your gradle file, 101 which in case of material was “compose/material/material”). 102 103 In your test module, create a variable pointing at your new directory: 104 105 ``` 106 const val GOLDEN_MATERIAL = "compose/material/material" 107 ``` 108 109#### Adding a screenshot test 110 111Here is an example of a minimal screenshot test for compose material. 112 113``` 114@LargeTest 115@RunWith(JUnit4::class) 116@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O) 117class CheckboxScreenshotTest { 118 @get:Rule val composeTestRule = createComposeRule() 119 @get:Rule val screenshotRule = AndroidXScreenshotTestRule(GOLDEN_MATERIAL) 120 121 @Test 122 fun checkBoxTest_checked() { 123 composeTestRule.setMaterialContent { 124 Checkbox(Modifier.wrapContentSize(Alignment.TopStart), 125 checked = true, 126 onCheckedChange = {} 127 ) 128 } 129 find(isToggleable()) 130 .captureToBitmap() 131 .assertAgainstGolden(screenshotRule, "checkbox_checked") 132 } 133} 134``` 135 136NOTE: The string “checkbox_checked” is the unique identifier of your golden in 137your module. We use that string to name the golden file so avoid special 138characters. Please avoid any substrings like: golden, image etc. as there is no 139need - instead just describe what the image contains. 140 141#### Guidance around diffing 142 143Try to take the smallest screenshot possible. This will reduce interference from 144other elements. 145 146By default we use a MSSIM comparer. This one is based on similarity. However we 147have quite a high bar currently which is 0.98 (1 is an exact match). You can 148provide your own threshold or even opt into a pixel perfect comparer for some 149reason. 150 151Note: The bigger screenshots you take the more you sacrifice in the precision as 152you can aggregate larger diffing errors, see the examples below. 153 154 155 156#### Generating your goldens in CI (Gerrit) 157 158Upload your CL to gerrit and run presubmit. You should see your test fail. 159 160Step 1: Click on the “Test” button below: 161 162 163 164Step 2: Click on the “Update scuba goldens” below: 165 166 167Step 3: Select the tests for which you want to update the golden images. Confirm 168the images look correct and click on “Approve Changes” 169 170 171Step 4: In the Approve changes dialog box, enter the following details and click 172on Approve: \ 173Select gerrit host as shown in image below \ 174Repo: platform/frameworks/support-golden \ 175Branch: androidx-main 176 177 178Step 5: Link your original CL with the new goldens CL by setting the same Topic 179field in both CLs (any arbitrary string will do). This tells Gerrit to submit 180the CLs together, effectively providing a reference from the original CL to the 181new goldens. And re-run presubmit. Your tests should now pass! 182 183 184#### Running manually / debugging 185 186Screenshot tests can be run locally using pixel 2 api33 emulator. Start the 187emulator using [these](#emulator) steps. 188 189Wait until the emulator is running and run the tests as you would on a regular 190device. 191 192``` 193$ ./gradlew <module>:cAT -Pandroid.testInstrumentationRunnerArguments.class=<class> 194``` 195 196If the test passes, the results are limited to a .textproto file for each 197screenshot test. If the test fails, the results will also contain the actual 198screenshot and, if available, the golden reference image and the diff between 199the two. Note that this means that if you want to regenerate the golden image, 200you have to remove the golden image before running the test. 201 202To get the screenshot related results from the device onto your workstation, you 203can run 204 205``` 206$ adb pull /sdcard/Android/data/<test-package>/cache/androidx_screenshots 207``` 208 209where test-package is the identifier of you test apk, e.g. 210androidx.compose.material.test 211 212#### Locally updating the golden images 213 214After you run a screenshot test and pull the results to a desired location, 215verify that the actual images are the correct ones and copy them to the golden 216screenshots directory (the one you use to create the AndroidXScreenshotTestRule 217with) using this script. 218 219``` 220androidx-main/frameworks/support/development/copy_screenshots_to_golden_repo.py \ 221--input-dir=/tmp/androidx_screenshots/ --output-dir=androidx-main/golden/<test>/ 222``` 223 224Repeat for all screenshots, then create and upload a CL in the golden 225repository. 226 227### What gets tested, and when {#affected-module-detector} 228 229With over 45000 tests executed on every CI run, it is necessary for us to run 230only a subset of our instrumentation tests in presubmit. We use the 231[AffectedModuleDetector](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:buildSrc/private/src/main/kotlin/androidx/build/dependencyTracker/AffectedModuleDetector.kt) 232to determine what projects have changed since the last merge. In turn, we only 233generate apks and test configurations for those changed modules and their 234dependencies. 235 236When changes are made that can't be associated with a module, are in the root of 237the checkout, or are within `buildSrc`, then all host tests and all device tests 238annotated with `@SmallTest` or `@MediumTest` will be run for all modules. 239 240Presubmit tests represent only a subset of the devices on which our tests run. 241The remaining devices are tested only in postsubmit. In postsubmit, all host and 242device tests are run for all modules. 243 244### Test annotations {#annotations} 245 246#### Test size and runners {#test-size} 247 248All device tests *should* be given a size annotation, which is one of: 249 250* [`@SmallTest`](https://developer.android.com/reference/androidx/test/filters/SmallTest) 251* [`@MediumTest`](https://developer.android.com/reference/androidx/test/filters/MediumTest) 252* [`@LargeTest`](https://developer.android.com/reference/androidx/test/filters/LargeTest) 253 254If a device test is *not* annotated with its size, it will be run as if it were 255`@LargeTest` by default. Host tests do not need to be annotated with their size, 256as all host tests are run regardless of size. 257 258This annotation can occur at either the class level or individual test level. 259 260Annotation | Max duration 261------------- | ------------ 262`@SmallTest` | 200ms 263`@MediumTest` | 1000ms 264`@LargeTest` | 100000ms 265 266#### Disabling tests {#disabling-tests} 267 268If you need to stop a host- or device-side test from running entirely, use 269JUnit's [`@Ignore`](http://junit.sourceforge.net/javadoc/org/junit/Ignore.html) 270annotation. Do *not* use Android's `@Suppress` annotation, which only works with 271Android test runners and will *not* work for host-side tests. 272 273#### Filtering devices {#filtering-devices} 274 275To restrict a test to a range of SDKs, use 276[`@SdkSuppress`](https://developer.android.com/reference/androidx/test/filters/SdkSuppress) 277which allows specifying a range with `minSdkVersion` and `maxSdkVersion`. This 278annotation also supports targeting a specific pre-release SDK with the 279`codeName` parameter. 280 281```java 282// Target SDKs 17 through 19, inclusive 283@SdkSuppress(minSdkVersion = 17, maxSdkVersion = 19) 284 285// Target pre-release SDK T only 286@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu") 287``` 288 289You may also gate portions of test implementation code using `SDK_INT` or 290[`BuildCompat.isAtLeast`](https://developer.android.com/reference/androidx/core/os/BuildCompat) 291methods. s To restrict to only physical devices, use 292[`@RequiresDevice`](https://developer.android.com/reference/androidx/test/filters/RequiresDevice). 293 294NOTE [Cuttlefish](https://source.android.com/setup/create/cuttlefish) is not 295affected by this annotation, only e.g. Studio emulators. If Cuttlefish is 296displaying behavior that differs from a physical device, they are considering 297that a bug in Cuttlefish, so please file those bugs instead of only looking for 298a workaround. 299 300### Animations in tests {#animations} 301 302Animations are disabled for tests by default. This helps avoid flakes due to 303timing and also makes tests faster. 304 305In rare cases, like testing the animations themselves, you may want to enable 306animations for a particular test or test class. For those cases, you can use the 307[`AnimationDurationScaleRule`](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:testutils/testutils-runtime/src/main/java/androidx/testutils/AnimationDurationScaleRule.kt). 308 309### Robolectric {#robolectric} 310 311Robolectric tests are supported in AndroidX; however, if you targeting a 312pre-release version of the Android SDK then you may see an error like 313 314``` 315java.lang.IllegalArgumentException: Package targetSdkVersion=31 > maxSdkVersion=30 316at org.robolectric.plugins.DefaultSdkPicker.configuredSdks(DefaultSdkPicker.java:118) 317at org.robolectric.plugins.DefaultSdkPicker.selectSdks(DefaultSdkPicker.java:69) 318``` 319 320You can force Robolectric to run using an earlier version of the platform SDK by 321creating a `<project>/src/test/resources/robolectric.properties` file with the 322following contents: 323 324``` 325# Robolectric currently doesn't support API 31, so we have to explicitly specify 30 as the target 326# sdk for now. Remove when no longer necessary. 327sdk=30 328``` 329 330## Using the emulator {#emulator} 331 332You can use the emulator or a real device to run tests. If you wish to use the 333emulator, you will need to access the AVD Manager (and your downloaded emulator 334images) using a separate "normal" instance of Android Studio. "Normal" means a 335non-Canary build of Studio that you would use for regular app development -- the 336important part being that it points to the Android SDK where your downloaded 337emulator images reside. You will need to open a project to get the Tools menu -- 338do NOT open the AndroidX project in the "normal" instance of Android Studio; 339instead, open a normal app or create a blank project using the app wizard. 340 341NOTE You can reuse the emulator and system images from a "normal" installation 342of Android Studio by linking the `emulator` and `system_images` directories to a 343standard Android SDK path and restarting Android Studio. **This is set up 344automatically by `studiow` on Google-managed devices with a standard Android SDK 345path.** In other cases, it may be set up manually with something like: `cd 346prebuilts/fullsdk-darwin ln -s ~/Library/Android/sdk/emulator emulator ln -s 347~/Library/Android/sdk/system-images system-images` (substituting `fullsdk-linux` 348and your local SDK path as appropriate) 349 350## Debugging tests 351 352### Using custom platform SDK sources {#sources} 353 354The platform SDK sources that are checked into the development branch may not 355match up with the build of Android present on the emulator or your physical 356device. As a result, the line numbers reported by the debugger may not match up 357the actual code being run. 358 359If you have a copy of the sources for the build against which you are debugging, 360you can manually specify your platform SDK source path: 361 3621. Click on a module (e.g. `appcompat`) in the `Project` view 3631. Press `Ctrl-Shift-A` and type "Module Settings", then run the action 3641. In the `Project Structure` dialog, navigate to `SDKs > Android API 29 365 Platform > Sourcepath` 3661. Use the `-` button to remove any paths that are present, then use the `+` 367 button to add the desired source path, ex. `<android checkout 368 root>/frameworks/base` if you are debugging against a locally-built system 369 image 370 371NOTE The `Project Structure` dialog reachable via `File > Project Structure` is 372**not** the same as the `Project Structure` dialog that will allow you to 373specify the SDK source path. You must use the "Module Settings" action as 374directed above. 375 376### Accessing FTL outputs 377 378When we run tests on Firebase Test Lab devices, we transfer the results and 379logcat output back to Android's test result infrastructure; however, FTL also 380captures screen recordings of the entire test run. 381 382To access these videos from the Android Test Investigate page for a failed test 383run: 384 385- For the failing test, go to `Artifacts tab` in the Android Test Investigate 386 page 387- Disable `Hide empty folders` (if enabled) by clicking on it 388- Under `Run artifacts`, click on "i" icon next to the test module to open the 389 Information tab 390- In the Information tab to the right, click on the link next to the `logs` 391 property 392 393The full logcat output and screen recording are available from the `Devices` tab 394by clicking on the test device under `Device details` and using the `Logs` and 395`Video` tabs, respectively. 396 397Per-test logcat output and videos are available from the `Test cases` tab. 398 399## Running unit and integration tests {#running} 400 401From Android Studio, right-click can be used to run most test targets, including 402source files, classes within a file, or individual test methods but **not** 403entire modules. To run a supported test target, right-click on the test target 404and then click `Run <name of test target>`. 405 406To run tests for an entire module such as `appcompat`, use `Run -> Edit 407configurations...` and use the `+` button to create a new `Android Instrumented 408Tests` configuration. Specify the module to be tested, give it a reasonable name 409(not "All Tests") and click `OK`, then use the `Run` menu to run the 410configuration. 411 412 413 414NOTE If you receive the error `JUnit version 3.8 or later expected` this means 415that Android Studio generated an Android JUnit configuration when you actually 416needed an Android Instrumented Tests configuration. Open the `Run -> Edit 417configurations...` dialog and delete the configuration from Android JUnit, then 418manually add a configuration in Android Instrumented Tests. 419 420### From the command line {#running-from-shell} 421 422Following a successful build, tests may be run against a particular AndroidX 423module using `gradlew`. 424 425To run all unit or integration tests in a specific project, run the following 426from `framework/support`: 427 428```shell 429# Run instrumentation tests on a connected device 430./gradlew <project-name>:connectedAndroidTest --info 431 432# Run instrumentation tests in Firebase Test Lab (remote) 433./gradlew <project-name>:ftlnexus4api21 434./gradlew <project-name>:ftlmediumphoneapi26 435./gradlew <project-name>:ftlmediumphoneapi30 436./gradlew <project-name>:ftlmediumphoneapi33 437./gradlew <project-name>:ftlmediumphoneapi34 438./gradlew <project-name>:ftlmediumphoneapi35 439 440./gradlew <project-name>:ftlmediumphoneapi28 (For compose tests only) 441 442# Run local unit tests 443./gradlew <project-name>:test 444``` 445 446substituting the Gradle project name (ex. `:core:core`). 447 448To run a specific instrumentation test in a given project, run 449 450```shell 451# Run instrumentation tests on a connected device 452./gradlew <project-name>:connectedAndroidTest --info \ 453 -Pandroid.testInstrumentationRunnerArguments.class=<fully-qualified-class>[\#testName] 454 455# Run instrumentation tests on in Firebase Test Lab (remote) 456./gradlew <project-name>:ftlmediumphoneapi30 --className=<fully-qualified-class> 457``` 458 459substituting the Gradle project name (ex. `viewpager`) and fully-qualified class 460name (ex. `androidx.viewpager.widget.ViewPagerTest`) of your test file, 461optionally followed by `\#testName` if you want to execute a single test in that 462file 463 464If you want to run a specific unit test, you can do it using 465[`--tests` filtering](https://docs.gradle.org/current/userguide/java_testing.html#test_filtering): 466 467```shell 468# Run a test for an Android library on a connected device 469./gradlew <project-name>:test --tests androidx.core.view.DisplayCompatTest 470 471# Run a test for a JVM library 472./gradlew <project-name>:testDebugUnitTest --tests 473androidx.core.view.DisplayCompatTest 474``` 475 476## Test apps {#testapps} 477 478Library developers are strongly encouraged to write test apps that exercise 479their library's public API surface. Test apps serve multiple purposes: 480 481* Integration testing and validation of API testability, when paired with 482 tests 483* Validation of API usability and developer experience, when paired with a use 484 case or critical user journey 485* Sample documentation, when embedded into API reference docs using the 486 [`@sample` and `@Sampled` annotations](/docs/api_guidelines/index.md#sample-usage) 487 488### Legacy test apps {#testapps-legacy} 489 490We have a set of legacy sample Android applications in projects suffixed with 491`-demos`. These applications do not have tests and should not be used as test 492apps for new APIs, but they may be useful for manual regression testing. 493 4941. Click `Run/Debug Configuration` on the top of the window. 4951. Select the app you want to run. 4961. Click 'Run' button. 497 498 499 500## Benchmarking {#benchmarking} 501 502AndroidX supports benchmarking - locally with Studio/Gradle, and continuously in 503post-submit. For more information on how to create and run benchmarks, see 504[Benchmarking](/docs/benchmarking.md). 505