Home | History | Annotate | Download | only in development
      1 # Self-Instrumenting Tests: A Complete Example
      2 
      3 [TOC]
      4 
      5 If you are new to Android platform development, you might find this complete
      6 example of adding a brand new instrumentation test from scratch useful to
      7 demonstrate the typical workflow involved.
      8 
      9 Note that this guide assumes that you already have some knowledge in the
     10 platform source tree workflow. If not, please refer to
     11 https://source.android.com/source/requirements. The example
     12 covered here is writing an new instrumentation test with target package set at
     13 its own test application package. If you are unfamiliar with the concept, please
     14 read through the [testing basics](../basics/index.md) page.
     15 
     16 This guide uses the follow test to serve as an sample:
     17 
     18 *   [Hello World Instrumentation Test](../../tests/example/instrumentation)
     19 
     20 It's recommended to browse through the code first to get a rough impression
     21 before proceeding.
     22 
     23 ## Deciding on a Source Location {#location}
     24 
     25 Typically your team will already have an established pattern of places to check
     26 in code, and places to add tests. Most team owns a single git repository, or
     27 share one with other teams but have a dedicated sub directory that contains
     28 component source code.
     29 
     30 Assuming the root location for your component source is at `<component source
     31 root>`, most components have `src` and `tests` folders under it, and some
     32 additional files such as `Android.mk` (or broken up into additional `.mk` files),
     33 the manifest file `AndroidManifest.xml`, and the test configuration file
     34 'AndroidTest.xml'.
     35 
     36 Since you are adding a brand new test, you'll probably need to create the
     37 `tests` directory next to your component `src`, and populate it with content.
     38 
     39 In some cases, your team might have further directory structures under `tests`
     40 due to the need to package different suites of tests into individual apks. And
     41 in this case, you'll need to create a new sub directory under `tests`.
     42 
     43 Regardless of the structure, you'll end up populating the `tests` directory or
     44 the newly created sub directory with files similar to what's in
     45 `instrumentation` directory in the sample gerrit change. The sections below will
     46 explain in further details of each file.
     47 
     48 ## Makefile
     49 
     50 Each new test module must have a makefile to direct the build system with module
     51 metadata, compile time depdencies and packaging instructions.
     52 
     53 [Latest version of the makefile](../../tests/example/instrumentation/Android.mk)
     54 
     55 
     56 A snapshot is included here for convenience:
     57 
     58 ```makefile
     59 LOCAL_PATH := $(call my-dir)
     60 
     61 include $(CLEAR_VARS)
     62 
     63 LOCAL_SRC_FILES := $(call all-java-files-under, src)
     64 LOCAL_MODULE_TAGS := tests
     65 LOCAL_PACKAGE_NAME := HelloWorldTests
     66 
     67 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
     68 LOCAL_CERTIFICATE := platform
     69 
     70 LOCAL_COMPATIBILITY_SUITE := device-tests
     71 
     72 include $(BUILD_PACKAGE)
     73 ```
     74 
     75 Some select remarks on the makefile:
     76 
     77 ```makefile
     78 LOCAL_MODULE_TAGS := tests
     79 ```
     80 
     81 This setting declares the module as a test module, which will instruct the build
     82 system to automatically skip proguard stripping, since that's typically
     83 problematic for tests.
     84 
     85 ```makefile
     86 LOCAL_PACKAGE_NAME := HelloWorldTests
     87 ```
     88 
     89 This setting is required when `BUILD_PACKAGE` is used later: it gives a name to
     90 your module, and the resulting apk will be named the same and with a `.apk`
     91 suffix, e.g. in this case, resulting test apk is named as `HelloWorldTests.apk`.
     92 In addition, this also defines a make target name for your module, so that you
     93 can use `make [options] <LOCAL_PACKAGE_NAME>` to build your test module and all
     94 its dependencies.
     95 
     96 ```makefile
     97 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
     98 ```
     99 
    100 This setting instructs the build system to incorporate the contents of the named
    101 modules into the resulting apk of current module. This means that each named
    102 module is expected to produce a `.jar` file, and its content will be used for
    103 resolving classpath references during compile time, as well as incorporated into
    104 the resulting apk.
    105 
    106 In this example, things that might be generally useful for tests:
    107 
    108 *   `android-support-test` is the prebuilt for Android Test Support Library,
    109     which included the new test runner `AndroidJUnitRunner`: a replacement for
    110     the now deprecated built-in `InstrumentationTestRunner`, with support for
    111     JUnit4 testing framework. Find out more at:
    112 
    113     *   https://google.github.io/android-testing-support-library/
    114 
    115     If you are building a new instrumentation module, you should always start
    116     with this library as your test runner.
    117 
    118 The platform source tree also included other useful testing frameworks such as
    119 `ub-uiautomator`, `mockito-target`, `easymock` and so on.
    120 
    121 ```makefile
    122 LOCAL_CERTIFICATE := platform
    123 ```
    124 
    125 This setting instructs the build system to sign the apk with the same
    126 certificate as the core platform. This is needed if your test uses a signature
    127 protected permission or API. Note that this is suitable for platform continuous
    128 testing, but should *not* be used in CTS test modules. Note that this example
    129 uses this certificat setting only for the purpose of illustration: the test code
    130 of the example does not actually need for the test apk to be signed with the
    131 special platform certificate.
    132 
    133 If you are writing an instrumentation for your component that lives outside of
    134 system server, that is, it's packaged more or less like a regular app apk,
    135 except that it's built into system image and may be a priveleged app, chances
    136 are that your instrumentation will be targeting the app package (see below
    137 section about manifest) of your component. In this case, your applicaiton
    138 makefile may have its own `LOCAL_CERTIFICATE` setting, and your instrumentation
    139 module should retain the same setting. This is because to target your
    140 instrumentation on the app under test, your test apk and app apk must be signed
    141 with the same certificate.
    142 
    143 In other cases, you don't need to have this setting at all: the build system
    144 will simply sign it with a default built-in certificate, based on the build
    145 variant, and it's typically called the `dev-keys`.
    146 
    147 ```makefile
    148 LOCAL_COMPATIBILITY_SUITE := device-tests
    149 ```
    150 
    151 This sets up the test to be easily discoverable by the TradeFederation test
    152 harness. Other suites can be added here such as CTS so that this test may be
    153 shared.
    154 
    155 ```makefile
    156 include $(BUILD_PACKAGE)
    157 ```
    158 
    159 This includes a core makefile in build system that performs the necessary steps
    160 to generate an apk based on the settings provided by the preceding variables.
    161 The generated apk will be named after `LOCAL_PACKAGE_NAME`, e.g.
    162 `HelloWorldTests.apk`. And if `tests` is used as `LOCAL_MODULE_TAGS` and there
    163 are no other customizations, you should be able to find your test apk in:
    164 
    165 *   `${OUT}/data/app/<LOCAL_PACKAGE_NAME>/<LOCAL_PACKAGE_NAME>.apk`
    166 
    167 e.g. `${OUT}/data/app/HelloWorldTests/HelloWorldTests.apk`
    168 
    169 ## Manifest file
    170 
    171 Just like a regular application, each instrumentation test module needs a
    172 manifest file. If you name the file as `AndroidManifest.xml` and provide it next
    173 to `Android.mk` for your test tmodule, it will get included automatically by the
    174 `BUILD_PACKAGE` core makefile.
    175 
    176 Before proceeding further, it's highly recommended to go through the external
    177 [documentation on manifest file](https://developer.android.com/guide/topics/manifest/manifest-intro.html)
    178 first.
    179 
    180 This gives an overview of basic components of a manifest file and their
    181 functionalities.
    182 
    183 [Latest Manifest File](../../tests/example/instrumentation/AndroidManifest.xml)
    184 
    185 A snapshot is included here for convenience:
    186 
    187 ```xml
    188 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    189     package="android.test.example.helloworld"
    190     android:sharedUserId="android.uid.system" >
    191 
    192     <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21" />
    193 
    194     <application>
    195         <uses-library android:name="android.test.runner" />
    196     </application>
    197 
    198     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
    199                      android:targetPackage="android.test.example.helloworld"
    200                      android:label="Hello World Test"/>
    201 
    202 </manifest>
    203 ```
    204 
    205 Some select remarks on the manifest file:
    206 
    207 ```xml
    208 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    209     package="android.test.example.helloworld"
    210 ```
    211 
    212 The `package` attribute is the application package name: this is the unique
    213 identifier that the Android application framework uses to identify an
    214 application (or in this context: your test application). Each user in the system
    215 can only install one application with that package name.
    216 
    217 Furthermore, this `package` attribute is the same as what
    218 [`ComponentName#getPackageName()`](https://developer.android.com/reference/android/content/ComponentName.html#getPackageName\(\))
    219 returns, and also the same you would use to interact with various `pm` sub
    220 commands via `adb shell`.
    221 
    222 Please also note that although the package name is typically in the same style
    223 as a Java package name, it actually has very few things to do with it. In other
    224 words, your application (or test) package may contain classes with any package
    225 names, though on the other hand, you could opt for simplicity and have your top
    226 level Java package name in your application or test identical to the application
    227 package name.
    228 
    229 ```xml
    230 android:sharedUserId="android.uid.system"
    231 ```
    232 
    233 This declares that at installation time, this apk should be granted the same
    234 user id, i.e. runtime identity, as the core platform. Note that this is
    235 dependent on the apk being signed with same certificate as the core platform
    236 (see `LOCAL_CERTIFICATE` in above section), yet they are different concepts:
    237 
    238 *   some permissions or APIs are signature protected, which requires same
    239     signing certificate
    240 *   some permissions or APIs requires the `system` user identity of the caller,
    241     which requires the calling package to share user id with `system`, if it's a
    242     separate package from core platform itself
    243 
    244 ```xml
    245 <uses-library android:name="android.test.runner" />
    246 ```
    247 
    248 This is required for all Instrumentation tests since the related classes are
    249 packaged in a separate framework jar library file, therefore requires additional
    250 classpath entries when the test package is invoked by application framework.
    251 
    252 ```xml
    253 android:targetPackage="android.test.example.helloworld"
    254 ```
    255 
    256 You might have noticed that the `targetPackage` here is declared the same as the
    257 `package` attribute declared in the `manifest` tag of this file. As mentioned in
    258 [testing basics](../basics/index.md), this category of instrumentation test are
    259 typically intended for testing framework APIs, so it's not very meaningful for
    260 them to have a specific targeted application package, other then itself.
    261 
    262 ## Test Configuration File
    263 
    264 In order to simplify test execution, you also need write a test configuration
    265 file for Android's test harness, [TradeFederation](https://source.android.com/devices/tech/test_infra/tradefed/).
    266 
    267 The test configuration can specify special device setup options and default
    268 arguments to supply the test class.
    269 
    270 [Latest Test Config File](../../tests/example/instrumentation/AndroidTest.xml)
    271 
    272 A snapshot is included here for convenience:
    273 
    274 ```xml
    275 <configuration description="Runs sample instrumentation test.">
    276   <target_preparer class="com.android.tradefed.targetprep.TestFilePushSetup"/>
    277   <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
    278     <option name="test-file-name" value="HelloWorldTests.apk"/>
    279   </target_preparer>
    280   <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"/>
    281   <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"/>
    282   <option name="test-suite-tag" value="apct"/>
    283   <option name="test-tag" value="SampleInstrumentationTest"/>
    284 
    285   <test class="com.android.tradefed.testtype.AndroidJUnitTest">
    286     <option name="package" value="android.test.example.helloworld"/>
    287     <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
    288   </test>
    289 </configuration>
    290 ```
    291 
    292 Some select remarks on the test configuration file:
    293 
    294 ```xml
    295 <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
    296   <option name="test-file-name" value="HelloWorldTests.apk"/>
    297 </target_preparer>
    298 ```
    299 This tells TradeFederation to install the HelloWorldTests.apk onto the target
    300 device using a specified target_preparer. There are many target preparers
    301 available to developers in TradeFederation and these can be used to ensure
    302 the device is setup properly prior to test execution.
    303 
    304 ```xml
    305 <test class="com.android.tradefed.testtype.AndroidJUnitTest">
    306   <option name="package" value="android.test.example.helloworld"/>
    307   <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
    308 </test>
    309 ```
    310 This specifies the TradeFederation test class to use to execute the test and
    311 passes in the package on the device to be executed and the test runner
    312 framework which is JUnit in this case.
    313 
    314 Look here for more information on [Test Module Configs](test-config.md)
    315 
    316 ## JUnit4 Features
    317 
    318 Using `android-support-test` library as test runner enables adoptation of new
    319 JUnit4 style test classes, and the sample gerrit change contains some very basic
    320 use of its features.
    321 
    322 [Latest source code](../../tests/example/instrumentation/src/android/test/example/helloworld/HelloWorldTest.java)
    323 
    324 While testing patterns are usually specific to component teams, there are some
    325 generally useful usage patterns.
    326 
    327 ```java
    328 @RunWith(JUnit4.class)
    329 public class HelloWorldTest {
    330 ```
    331 
    332 A significant difference in JUnit4 is that tests are no longer required to
    333 inherit from a common base test class; instead, you write tests in plain Java
    334 classes and use annotation to indicate certain test setup and constraints. In
    335 this example, we are instructing that this class should be run as a JUnit4 test.
    336 
    337 ```java
    338     @BeforeClass
    339     public static void beforeClass() {
    340     ...
    341     @AfterClass
    342     public static void afterClass() {
    343     ...
    344     @Before
    345     public void before() {
    346     ...
    347     @After
    348     public void after() {
    349     ...
    350     @Test
    351     @SmallTest
    352     public void testHelloWorld() {
    353     ...
    354 ```
    355 
    356 The `@Before` and `@After` annotations are used on methods by JUnit4 to perform
    357 pre test setup and post test teardown. Similarly, the `@BeforeClass` and
    358 `@AfterClass` annotations are used on methods by JUnit4 to perform setup before
    359 executing all tests in a test class, and teardown afterwards. Note that the
    360 class-scope setup and teardown methods must be static. As for the test methods,
    361 unlike in earlier version of JUnit, they no longer need to start the method name
    362 with `test`, instead, each of them must be annotated with `@Test`. As usual,
    363 test methods must be public, declare no return value, take no parameters, and
    364 may throw exceptions.
    365 
    366 **Important**: the test methods themselves are annotated with `@Test`
    367 annotation; and note that for tests to be executed via APCT, they must be
    368 annotated with test sizes: the example annotated method `testHelloWorld` as
    369 `@SmallTest`. The annotation may be applied at method scope, or class scope.
    370 
    371 ## Accessing `Instrumentation`
    372 
    373 Although not covered in the basic hello world example, it's fairly common for an
    374 Android test to require access `Instrumentation` instance: this is the core API
    375 interface that provides access to application contexts, activity lifecycle
    376 related test APIs and more.
    377 
    378 Because the JUnit4 tests no longer require a common base class, it's no longer
    379 necessary to obtain `Instrumentation` instance via
    380 `InstrumentationTestCase#getInstrumentation()`, instead, the new test runner
    381 manages it via [`InstrumentationRegistry`](https://developer.android.com/reference/android/support/test/InstrumentationRegistry.html)
    382 where contextual and environmental setup created by instrumentation framework is
    383 stored.
    384 
    385 To access the instance of `Instrumentation` class, simply call static method
    386 `getInstrumentation()` on `InstrumentationRegistry` class:
    387 
    388 ```java
    389 Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation()
    390 ```
    391 
    392 ## Build & Test Locally:
    393 
    394 Follow these [Instructions](instrumentation.md)
    395