• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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