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