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