1# Instrumentation Targeting an Application: 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* frameworks/base/packages/Shell/tests 19 20It's recommended to browse through the code first to get a rough impression 21before proceeding. 22 23## Deciding on a Source Location 24 25Because the instrumentation test will be targeting an application, the convention 26is to place the test source code in a `tests` directory under the root of your 27component source directory in platform source tree. 28 29See more discussions about source location in the [end-to-end example for 30self-instrumenting tests](instr-self-e2e.md#location). 31 32## Makefile 33 34Each new test module must have a makefile to direct the build system with module 35metadata, compile time depdencies and packaging instructions. 36 37frameworks/base/packages/Shell/tests/Android.mk 38 39A snapshot is included here for convenience: 40 41```makefile 42LOCAL_PATH := $(call my-dir) 43include $(CLEAR_VARS) 44 45LOCAL_MODULE_TAGS := tests 46 47LOCAL_SRC_FILES := $(call all-java-files-under, src) 48 49LOCAL_JAVA_LIBRARIES := android.test.runner 50 51LOCAL_STATIC_JAVA_LIBRARIES := ub-uiautomator junit legacy-android-test 52 53LOCAL_PACKAGE_NAME := ShellTests 54LOCAL_INSTRUMENTATION_FOR := Shell 55 56LOCAL_COMPATIBILITY_SUITE := device-tests 57 58LOCAL_CERTIFICATE := platform 59include $(BUILD_PACKAGE) 60``` 61 62Some select remarks on the makefile: 63 64```makefile 65LOCAL_MODULE_TAGS := tests 66``` 67 68This setting declares the module as a test module, which will instruct the build 69system to automatically skip proguard stripping, since that's typically 70problematic for tests. 71 72```makefile 73LOCAL_CERTIFICATE := platform 74``` 75 76This setting instructs the build system to sign the test application package 77with the platform certificate. This is because for a test application package to 78be able to instrument on the targeted application package, these two packages 79must be signed with the same certificate; otherwise allowing packages to be 80instrumented on arbitrarily would be a security concern. To find out the signing 81certificate of the application packge you are testing, look for 82`LOCAL_CERTIFICATE` in its `Android.mk`; and if there isn't one, simply skip 83this field in your test application makefile as well. 84 85```makefile 86LOCAL_JAVA_LIBRARIES := android.test.runner 87``` 88 89This setting tells the build system to put Java library `android.test.runner` on 90classpath during compilation, as opposed to statically incorporating the library 91into the current package. This is typically done for Java code that is 92referenced by the code in current package, and will be automatically placed on 93package classpath at runtime. In the context of tests for application, strictly 94speaking, both framework APIs and code in application under test fall into this 95category, however, the former is done via implicit rules by build system at 96compile time and by framework at runtime, and the latter is done via 97`LOCAL_INSTRUMENTATION_FOR` (see below) at compile time and via 98`android:targetPackage` (see below) in manifest by instrumentation framework at 99runtime. 100 101```makefile 102LOCAL_STATIC_JAVA_LIBRARIES := ub-uiautomator junit legacy-android-test 103``` 104 105This setting instructs the build system to incorporate the contents of the named 106modules into the resulting apk of current module. This means that each named 107module is expected to produce a `.jar` file, and its content will be used for 108resolving classpath references during compile time, as well as incorporated into 109the resulting apk. 110 111 112The platform source tree also included other useful testing frameworks such as 113`ub-uiautomator`, `easymock` and so on. 114 115```makefile 116LOCAL_PACKAGE_NAME := ShellTests 117``` 118 119This setting is required if `BUILD_PACKAGE` when used later: it gives a name to 120your module, and the resulting apk will be named the same and with a `.apk` 121suffix, e.g. in this case, resulting test apk is named as 122`ShellTests.apk`. In addition, this also defines a make target name 123for your module, so that you can use `make [options] <LOCAL_PACKAGE_NAME>` to 124build your test module and all its dependencies. 125 126```makefile {# LOCAL_INSTRUMENTATION_FOR} 127LOCAL_INSTRUMENTATION_FOR := Shell 128``` 129 130As mentioned, during execution of an instrumentation test, the application under 131test is restarted with the instrumentation code injected for execution. The test 132can reference any classes and its instances of the application under test. This 133means that the test code may contain references to classes defined by the 134application under test, so during compile time, the build system needs to 135properly resolve such references. This setting provides the module name of 136application under test, which should match the `LOCAL_PACKAGE_NAME` of in the 137makefile for your application. At compile time, the build system will try to 138look up the intermediate files for the named module, and use them on the 139classpath for the Java compiler. 140 141```makefile 142LOCAL_COMPATIBILITY_SUITE := device-tests 143``` 144 145This line builds the testcase as part of the device-tests suite, which is 146meant to target a specific device and not a general ABI. If only the ABI 147needs to be targetted, it can be swapped with 'general-tests'. 148 149```makefile 150include $(BUILD_PACKAGE) 151``` 152 153This includes a core makefile in build system that performs the necessary steps 154to generate an apk based on the settings provided by the preceding variables. 155The generated apk will be named after `LOCAL_PACKAGE_NAME`, e.g. 156`SettingsGoogleUnitTests.apk`. And if `tests` is used as `LOCAL_MODULE_TAGS` and 157there are no other customizations, you should be able to find your test apk in: 158 159* `${OUT}/data/app/<LOCAL_PACKAGE_NAME>/<LOCAL_PACKAGE_NAME>.apk` 160 161e.g. `${OUT}/data/app/ShellTests/ShellTests.apk` 162 163## Manifest file 164 165Just like a regular application, each instrumentation test module needs a 166manifest file. If you name the file as `AndroidManifest.xml` and provide it next 167to `Android.mk` for your test tmodule, it will get included automatically by the 168`BUILD_PACKAGE` core makefile. 169 170Before proceeding further, it's highly recommended to go through the external 171[documentation on manifest file](https://developer.android.com/guide/topics/manifest/manifest-intro.html) 172first. 173 174This gives an overview of basic components of a manifest file and their 175functionalities. 176 177Latest version of the manifest file for the sample gerrit change can be accessed 178at: 179https://android.googlesource.com/platform/frameworks/base/+/master/packages/Shell/tests/AndroidManifest.xml 180 181A snapshot is included here for convenience: 182 183```xml 184<manifest xmlns:android="http://schemas.android.com/apk/res/android" 185 package="com.android.shell.tests"> 186 187 <application> 188 <uses-library android:name="android.test.runner" /> 189 190 <activity 191 android:name="com.android.shell.ActionSendMultipleConsumerActivity" 192 android:label="ActionSendMultipleConsumer" 193 android:theme="@android:style/Theme.NoDisplay" 194 android:noHistory="true" 195 android:excludeFromRecents="true"> 196 <intent-filter> 197 <action android:name="android.intent.action.SEND_MULTIPLE" /> 198 <category android:name="android.intent.category.DEFAULT" /> 199 <data android:mimeType="*/*" /> 200 </intent-filter> 201 </activity> 202 </application> 203 204 <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" 205 android:targetPackage="com.android.shell" 206 android:label="Tests for Shell" /> 207 208</manifest> 209``` 210 211Some select remarks on the manifest file: 212 213```xml 214<manifest xmlns:android="http://schemas.android.com/apk/res/android" 215 package="com.android.shell.tests"> 216``` 217 218The `package` attribute is the application package name: this is the unique 219identifier that the Android application framework uses to identify an 220application (or in this context: your test application). Each user in the system 221can only install one application with that package name. 222 223Since this is a test application package, independent from the application 224package under test, a different package name must be used: one common convention 225is to add a suffix `.test`. 226 227Furthermore, this `package` attribute is the same as what 228[`ComponentName#getPackageName()`](https://developer.android.com/reference/android/content/ComponentName.html#getPackageName\(\)) 229returns, and also the same you would use to interact with various `pm` sub 230commands via `adb shell`. 231 232Please also note that although the package name is typically in the same style 233as a Java package name, it actually has very few things to do with it. In other 234words, your application (or test) package may contain classes with any package 235names, though on the other hand, you could opt for simplicity and have your top 236level Java package name in your application or test identical to the application 237package name. 238 239```xml 240<uses-library android:name="android.test.runner" /> 241``` 242 243This is required for all Instrumentation tests since the related classes are 244packaged in a separate framework jar library file, therefore requires additional 245classpath entries when the test package is invoked by application framework. 246 247```xml 248android:targetPackage="com.android.shell" 249``` 250 251This sets the target package of the instrumentation to `com.android.shell.tests`. 252When the instrumentation is invoked via `am instrument` command, the framework 253restarts `com.android.shell.tests` process, and injects instrumentation code into 254the process for test execution. This also means that the test code will have 255access to all the class instances running in the application under test and may 256be able to manipulate state depends on the test hooks exposed. 257 258## Test Configuration File 259 260In order to simplify test execution, you also need write a test configuration 261file for Android's test harness, [TradeFederation](https://source.android.com/devices/tech/test_infra/tradefed/). 262 263The test configuration can specify special device setup options and default 264arguments to supply the test class. 265 266The config can be found: 267frameworks/base/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.javast.java 268 269A snapshot is included here for convenience: 270 271```xml 272<configuration description="Runs Tests for Shell."> 273 <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> 274 <option name="test-file-name" value="ShellTests.apk" /> 275 </target_preparer> 276 277 <option name="test-suite-tag" value="apct" /> 278 <option name="test-tag" value="ShellTests" /> 279 <test class="com.android.tradefed.testtype.AndroidJUnitTest" > 280 <option name="package" value="com.android.shell.tests" /> 281 <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" /> 282 </test> 283</configuration> 284``` 285 286Some select remarks on the test configuration file: 287 288```xml 289<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> 290 <option name="test-file-name" value="ShellTests.apk"/> 291</target_preparer> 292``` 293This tells TradeFederation to install the ShellTests.apk onto the target 294device using a specified target_preparer. There are many target preparers 295available to developers in TradeFederation and these can be used to ensure 296the device is setup properly prior to test execution. 297 298```xml 299<test class="com.android.tradefed.testtype.AndroidJUnitTest"> 300 <option name="package" value="com.android.shell.tests"/> 301 <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/> 302</test> 303``` 304This specifies the TradeFederation test class to use to execute the test and 305passes in the package on the device to be executed and the test runner 306framework which is JUnit in this case. 307 308Look here for more information on [Test Module Configs](test-config.md) 309 310## JUnit4 Features 311 312Using `android-support-test` library as test runner enables adoptation of new 313JUnit4 style test classes, and the sample gerrit change contains some very basic 314use of its features. 315 316Latest source code for the sample gerrit change can be accessed at: 317frameworks/base/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.javast.java 318 319While testing patterns are usually specific to component teams, there are some 320generally useful usage patterns. 321 322```java 323@SmallTest 324@RunWith(AndroidJUnit4.class) 325public final class FeatureFactoryImplTest { 326``` 327 328A significant difference in JUnit4 is that tests are no longer required to 329inherit from a common base test class; instead, you write tests in plain Java 330classes and use annotation to indicate certain test setup and constraints. In 331this example, we are instructing that this class should be run as an Android 332JUnit4 test. 333 334The `@SmallTest` annotation specified a test size for the entire test class: all 335test methods added into this test class inherit this test size annotation. 336pre test class setup, post test tear down, and post test class tear down: 337similar to `setUp` and `tearDown` methods in JUnit4. 338`Test` annotation is used for annotating the actual test. 339 340**Important**: the test methods themselves are annotated with `@Test` 341annotation; and note that for tests to be executed via APCT, they must be 342annotated with test sizes. Such annotation may be applied at method scope, or 343class scope. 344 345```java 346 @Before 347 public void setup() { 348 ... 349 @Test 350 public void testGetProvider_shouldCacheProvider() { 351 ... 352``` 353 354The `@Before` annotation is used on methods by JUnit4 to perform pre test setup. 355Although not used in this example, there's also `@After` for post test teardown. 356Similarly, the `@BeforeClass` and `@AfterClass` annotations are can be used on 357methods by JUnit4 to perform setup before executing all tests in a test class, 358and teardown afterwards. Note that the class-scope setup and teardown methods 359must be static. 360 361As for the test methods, unlike in earlier version of JUnit, they no longer need 362to start the method name with `test`, instead, each of them must be annotated 363with `@Test`. As usual, test methods must be public, declare no return value, 364take no parameters, and may throw exceptions. 365 366```java 367 Context context = InstrumentationRegistry.getTargetContext(); 368``` 369 370Because the JUnit4 tests no longer require a common base class, it's no longer 371necessary to obtain `Context` instances via `getContext()` or 372`getTargetContext()` via base class methods; instead, the new test runner 373manages them via [`InstrumentationRegistry`](https://developer.android.com/reference/android/support/test/InstrumentationRegistry.html) 374where contextual and environmental setup created by instrumentation framework is 375stored. Through this class, you can also call: 376 377* `getInstrumentation()`: the instance to the `Instrumentation` class 378* `getArguments()`: the command line arguments passed to `am instrument` via 379 `-e <key> <value>` 380 381## Build & Test Locally 382 383Follow these [Instructions](instrumentation.md) 384