| Index: testing/android/docs/instrumentation.md
|
| diff --git a/testing/android/docs/instrumentation.md b/testing/android/docs/instrumentation.md
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..c4b26d871010af4b024981c0f323ea76854bb856
|
| --- /dev/null
|
| +++ b/testing/android/docs/instrumentation.md
|
| @@ -0,0 +1,263 @@
|
| +# Android Instrumentation Tests
|
| +
|
| +Instrumentation tests are Java tests based on
|
| +[`android.app.Instrumentation`](https://developer.android.com/reference/android/app/Instrumentation.html).
|
| +They run on a device.
|
| +
|
| +[TOC]
|
| +
|
| +## Writing an instrumentation test
|
| +
|
| +Currently, an instrumentation test is just a JUnit3-style test based on
|
| +[android.test.InstrumentationTestCase](https://developer.android.com/reference/android/test/InstrumentationTestCase.html).
|
| +(This will change starting in [Android N](https://en.wikipedia.org/wiki/Android_Nougat).)
|
| +
|
| +Writing an instrumentation test case can be simple, e.g.
|
| +
|
| +```java
|
| +package org.chromium.sample.test;
|
| +
|
| +import android.test.InstrumentationTestCase;
|
| +
|
| +public class MyInstrumentationTest extends InstrumentationTestCase {
|
| +
|
| + // Note that, because it's a JUnit3-style test, the test method *must*
|
| + // start with "test".
|
| + public void testTheFirst() {
|
| + bool writingInstrumentationTestsCanBeEasy = true;
|
| +
|
| + // InstrumentationTestCase inherits the assert* methods through
|
| + // junit.framework.TestCase.
|
| + assertTrue(writingInstrumentationTestsCanBeEasy);
|
| + }
|
| +
|
| + public void testTheSecond() {
|
| + bool writingInstrumentationTestsIsAlwaysEasy = false;
|
| + assertFalse(writingInstrumentationTestsIsAlwaysEasy);
|
| + }
|
| +}
|
| +```
|
| +
|
| +After writing a test, you can run it by:
|
| +
|
| + - Adding the file to the relevant gn target if the entire file is new.
|
| +Typically, the "relevant gn target" is simply the target containing the
|
| +other files in the same directory.
|
| + - Rebuild.
|
| + - Run the test using the process described [here](/testing/android/docs/todo.md).
|
| +
|
| +## Instrumentation test features
|
| +
|
| +In many cases, Chromium has extended the instrumentation test framework
|
| +classes to implement additional features.
|
| +
|
| +### Test runners
|
| +
|
| +[todo](/testing/android/docs/todo.md)
|
| +
|
| +### Test cases
|
| +
|
| +[todo](/testing/android/docs/todo.md)
|
| +
|
| +### Annotations
|
| +
|
| +Instrumentation tests in Chromium use a wide variety of annotations to control
|
| +and manipulate test execution. Some of these are implemented in Chromium, while
|
| +others are pulled in from outside. They include:
|
| +
|
| +#### Size annotations
|
| +
|
| +Size annotations are used primarily by the test runner to determine the length
|
| +of time to wait before considering a test hung (i.e., its timeout duration).
|
| +
|
| +Several of the annotations are Android APIs from
|
| +[android.test.suitebuilder.annotation](https://developer.android.com/reference/android/test/suitebuilder/annotation/package-summary.html)
|
| +(prior to [Android N](https://en.wikipedia.org/wiki/Android_Nougat)) or
|
| +[android.support.test.filters](https://developer.android.com/reference/android/support/test/filters/package-summary.html)
|
| +(starting in Android N). These are all fairly self-explanatory:
|
| +
|
| + - [`@SmallTest`](https://developer.android.com/reference/android/support/test/filters/SmallTest.html) (timeout: **1 minute**)
|
| + - [`@MediumTest`](https://developer.android.com/reference/android/support/test/filters/MediumTest.html) (timeout: **3 minutes**)
|
| + - [`@LargeTest`](https://developer.android.com/reference/android/support/test/filters/LargeTest.html) (timeout: **5 minutes**)
|
| +
|
| +A few additional size annotations are provided in
|
| +[//base](https://chromium.googlesource.com/chromium/src/+/master/base):
|
| +
|
| + - [`@EnormousTest`](https://chromium.googlesource.com/chromium/src/+/master/base/test/android/javatests/src/org/chromium/base/test/util/EnormousTest.java)
|
| +(timeout: **10 minutes**) Typically used for tests that require WiFi.
|
| + - [`@IntegrationTest`](https://chromium.googlesource.com/chromium/src/+/master/base/test/android/javatests/src/org/chromium/base/test/util/IntegrationTest.java)
|
| +(timeout: **30 minutes**) Used for tests that run against real services.
|
| + - [`@Manual`](https://chromium.googlesource.com/chromium/src/+/master/base/test/android/javatests/src/org/chromium/base/test/util/Manual.java)
|
| +(timeout: **10 hours**) Used for manual tests.
|
| +
|
| +Beware that the timeout durations for these annotations are subject to
|
| +change, though they rarely do. These values are defined
|
| +[here](https://chromium.googlesource.com/chromium/src/+/master/build/android/pylib/local/device/local_device_instrumentation_test_run.py#20).
|
| +
|
| +#### Annotations that disable tests
|
| +
|
| +There are several annotations that control whether or not a test runs.
|
| +Some are conditional, others are not.
|
| +
|
| +##### Unconditional disabling
|
| +
|
| +Two annotations disable a test unless a user specifically asks for tests
|
| +annotated with that annotation to be run
|
| +(e.g., via passing `-A DisabledTest` to the test runner).
|
| +Note that these are both implemented in Chromium.
|
| +There are versions of @DisabledTest and @FlakyTest in Android that do not allow users to provide a message field.
|
| +
|
| + - [`@DisabledTest`](https://chromium.googlesource.com/chromium/src/+/master/base/test/android/javatests/src/org/chromium/base/test/util/DisabledTest.java)`(message = "")`
|
| + - [`@FlakyTest`](https://chromium.googlesource.com/chromium/src/+/master/base/test/android/javatests/src/org/chromium/base/test/util/FlakyTest.java)`(message = "")`
|
| +
|
| +In both cases, `message` is a message that should describe why the test is
|
| +disabled or marked as flaky. It should include a crbug link.
|
| +
|
| +##### Conditional disabling
|
| +
|
| +There are two primary annotation categories that conditionally disable tests:
|
| +**@DisableIf** and **@Restriction**. The **@DisableIf** annotations are intended
|
| +to temporarily disable a test in certain scenarios where it *should* work but
|
| +doesn't. In contrast, the **@Restriction** annotation is intended to
|
| +permanently limit a test to specific configurations. It signifies that the test
|
| +was not, is not, and will not be intended to run beyond those configurations.
|
| +In both cases, conditional disabling manifests as a skipped test.
|
| +
|
| +**@DisableIf.Build** allows for conditional test disabling based on values in
|
| +[`android.os.Build`](https://developer.android.com/reference/android/os/Build.html):
|
| +
|
| +```java
|
| +@DisableIf.Build(
|
| +
|
| + // Describes why the test is disabled.
|
| + message = "",
|
| +
|
| + // Disables the test on SDK levels that match the given conditions.
|
| + // Checks against Build.VERSION.SDK_INT.
|
| + sdk_is_greater_than = 0,
|
| + sdk_is_less_than = Integer.MAX_VALUE,
|
| +
|
| + // Disables the test on devices that support the given ABI
|
| + // (e.g. "arm64-v8a"). Checks against:
|
| + // - Build.SUPPORTED_ABIS on L+
|
| + // - Build.CPU_ABI and Build.CPU_ABI2 otherwise
|
| + supported_abis_includes = "",
|
| +
|
| + // Disables the test on devices with hardware that matches the given
|
| + // value. Checks against Build.HARDWARE.
|
| + hardware_is = "",
|
| +
|
| + // Disables the test on devices with product names that contain the
|
| + // given value. Checks against Build.PRODUCT.
|
| + product_name_includes = "",
|
| +
|
| +)
|
| +```
|
| +
|
| +**@DisableIf.Device** allows for conditional test disabling based on whether
|
| +a device is a phone, a tablet, or a "large tablet" as determined by
|
| +[org.chromium.ui.base.DeviceFormFactor](https://chromium.googlesource.com/chromium/src/+/master/ui/android/java/src/org/chromium/ui/base/DeviceFormFactor.java).
|
| +Note that this is currently only available to tests in
|
| +[//chrome](https://chromium.googlesource.com/chromium/src/+/master/chrome/)
|
| +or code that uses //chrome.
|
| +
|
| +```java
|
| +@DisableIf.Device(
|
| + // Disables the test on devices that match the given type(s) as described
|
| + // above.
|
| + type = {}
|
| +)
|
| +```
|
| +
|
| +**@Restriction** currently allows for conditional test disabling based on device
|
| +type, device performance, internet connectivity, whether Google Play Services is
|
| +up to date, and whether the build was an official one.
|
| +
|
| +```java
|
| +@Restriction(
|
| + // Possible values include:
|
| + //
|
| + // base:
|
| + // - Restriction.RESTRICTION_TYPE_LOW_END_DEVICE
|
| + // Restricts the test to low-end devices as determined by SysUtils.isLowEndDevice().
|
| + //
|
| + // - Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE
|
| + // Restricts the test to non-low-end devices as determined by SysUtils.isLowEndDevice().
|
| + //
|
| + // - Restriction.RESTRICTION_TYPE_INTERNET
|
| + // Restricts the test to devices that have an internet connection.
|
| + //
|
| + // chrome:
|
| + // - ChromeRestriction.RESTRICTION_TYPE_GOOGLE_PLAY_SERVICES
|
| + // Restricts the test to devices with up-to-date versions of Google Play Services.
|
| + //
|
| + // - ChromeRestriction.RESTRICTION_TYPE_PHONE
|
| + // Restricts the test to phones as determined by DeviceFormFactor.
|
| + //
|
| + // - ChromeRestriction.RESTRICTION_TYPE_TABLET
|
| + // Restricts the test to tablets as determined by DeviceFormFactor.
|
| + //
|
| + // - ChromeRestriction.RESTRICTION_TYPE_OFFICIAL_BUILD
|
| + // Restricts the test to official builds as determined by ChromeVersionInfo.isOfficialBuild().
|
| + value = {}
|
| +)
|
| +```
|
| +
|
| +**@MinAndroidSdkLevel** is similar to @Restriction in purpose in that it's
|
| +intended to permanently limit a test to only recent versions of Android.
|
| +
|
| +```java
|
| +@MinAndroidSdkLevel(
|
| + // The minimum SDK level at which this test should be executed. Checks
|
| + // against Build.VERSION.SDK_INT.
|
| + value = 0
|
| +)
|
| +```
|
| +
|
| +#### Annotations that affect how a test is run
|
| +
|
| +Several annotations affect how a test is run in interesting or nontrivial ways.
|
| +
|
| +**@CommandLineFlags.Add** and **@CommandLineFlags.Remove** manipulate Chrome's
|
| +command-line flags on a per-test basis (i.e., the flags handled by
|
| +[`org.chromium.base.CommandLine`](https://chromium.googlesource.com/chromium/src/+/master/base/android/java/src/org/chromium/base/CommandLine.java) and
|
| +[`base::CommandLine`](https://chromium.googlesource.com/chromium/src/+/master/base/command_line.h)).
|
| +
|
| +```java
|
| +@CommandLineFlags.Add(
|
| + // The flags to add to the command line for this test. These can be
|
| + // anything and typically should include the leading dashes (e.g. "--foo").
|
| + value = {}
|
| +)
|
| +
|
| +@CommandLineFlags.Remove(
|
| + // The flags to remove from the command line for this test. These can only
|
| + // be flags added via @CommandLineFlags.Add. Flags already present in the
|
| + // command-line file on the device are only present in the native
|
| + // CommandLine object and cannot be manipulated.
|
| + value = {}
|
| +)
|
| +```
|
| +
|
| +#### Feature annotations
|
| +
|
| +**@Feature** has been used inconsistently in Chromium to group tests across
|
| +test cases according to the feature they're testing.
|
| +
|
| +```java
|
| +@Feature(
|
| + // The features associated with this test. These can be anything.
|
| + value = {}
|
| +)
|
| +```
|
| +
|
| +@Feature doesn't have an inherent function, but it can be used to filter tests
|
| +via the test runner's
|
| +[-A/--annotation](/testing/android/docs/todo.md) and
|
| +[-E/--exclude-annotation](/testing/android/docs/todo.md) flags. For example,
|
| +this would run only the tests with @Feature annotations containing at least
|
| +"Sync" in `chrome_public_test_apk`:
|
| +
|
| +```bash
|
| +out/Debug/bin/run_chrome_public_test_apk -A Feature=Sync
|
| +```
|
|
|