blob: 8baa35de88e8ecb15ebfbb7aa6e8166157e0becf [file] [log] [blame]
Scott Main50e990c2012-06-21 17:14:39 -07001page.title=Activity Testing
2parent.title=Testing
3parent.link=index.html
4@jd:body
5
6<div id="qv-wrapper">
7 <div id="qv">
8 <h2>In this document</h2>
9 <ol>
10 <li>
11 <a href="#ActivityTestAPI">The Activity Testing API</a>
12 <ol>
13 <li>
14 <a href="#ActivityInstrumentationTestCase2">ActivityInstrumentationTestCase2</a>
15 </li>
16 <li>
17 <a href="#ActivityUnitTestCase">ActivityUnitTestCase</a>
18 </li>
19 <li>
20 <a href="#SingleLaunchActivityTestCase">SingleLaunchActivityTestCase</a>
21 </li>
22 <li>
23 <a href="#MockObjectNotes">Mock objects and activity testing</a>
24 </li>
25 <li>
26 <a href="#AssertionNotes">Assertions for activity testing</a>
27 </li>
28 </ol>
29 </li>
30 <li>
31 <a href="#WhatToTest">What to Test</a>
32 </li>
33 <li>
34 <a href="#NextSteps">Next Steps</a>
35 </li>
36 <li>
37 <a href="#UITesting">Appendix: UI Testing Notes</a>
38 <ol>
39 <li>
40 <a href="#RunOnUIThread">Testing on the UI thread</a>
41 </li>
42 <li>
43 <a href="#NotouchMode">Turning off touch mode</a>
44 </li>
45 <li>
46 <a href="#UnlockDevice">Unlocking the Emulator or Device</a>
47 </li>
48 <li>
49 <a href="#UITestTroubleshooting">Troubleshooting UI tests</a>
50 </li>
51 </ol>
52 </li>
53 </ol>
54<h2>Key Classes</h2>
55 <ol>
56 <li>{@link android.test.InstrumentationTestRunner}</li>
57 <li>{@link android.test.ActivityInstrumentationTestCase2}</li>
58 <li>{@link android.test.ActivityUnitTestCase}</li>
59 </ol>
60<h2>Related Tutorials</h2>
61 <ol>
62 <li>
63 <a href="{@docRoot}tools/testing/activity_test.html">Activity Testing Tutorial</a>
64 </li>
65 </ol>
66<h2>See Also</h2>
67 <ol>
68 <li>
69 <a href="{@docRoot}tools/testing/testing_eclipse.html">
70 Testing from Eclipse with ADT</a>
71 </li>
72 <li>
73 <a href="{@docRoot}tools/testing/testing_otheride.html">
74 Testing from Other IDEs</a>
75 </li>
76 </ol>
77 </div>
78</div>
79<p>
kmccormick76dfc022013-04-03 12:41:12 -070080 Activity testing is particularly dependent on the Android instrumentation framework.
Scott Main50e990c2012-06-21 17:14:39 -070081 Unlike other components, activities have a complex lifecycle based on callback methods; these
82 can't be invoked directly except by instrumentation. Also, the only way to send events to the
83 user interface from a program is through instrumentation.
84</p>
85<p>
86 This document describes how to test activities using instrumentation and other test
87 facilities. The document assumes you have already read
88 <a href="{@docRoot}tools/testing/testing_android.html">Testing Fundamentals</a>,
89 the introduction to the Android testing and instrumentation framework.
90</p>
91<h2 id="ActivityTestAPI">The Activity Testing API</h2>
92<p>
93 The activity testing API base class is {@link android.test.InstrumentationTestCase},
94 which provides instrumentation to the test case subclasses you use for Activities.
95</p>
96<p>
97 For activity testing, this base class provides these functions:
98</p>
99<ul>
100 <li>
101 Lifecycle control: With instrumentation, you can start the activity under test, pause it,
102 and destroy it, using methods provided by the test case classes.
103 </li>
104 <li>
105 Dependency injection: Instrumentation allows you to create mock system objects such as
106 Contexts or Applications and use them to run the activity under test. This
107 helps you control the test environment and isolate it from production systems. You can
108 also set up customized Intents and start an activity with them.
109 </li>
110 <li>
111 User interface interaction: You use instrumentation to send keystrokes or touch events
112 directly to the UI of the activity under test.
113 </li>
114</ul>
115<p>
116 The activity testing classes also provide the JUnit framework by extending
117 {@link junit.framework.TestCase} and {@link junit.framework.Assert}.
118</p>
119<p>
120 The two main testing subclasses are {@link android.test.ActivityInstrumentationTestCase2} and
121 {@link android.test.ActivityUnitTestCase}. To test an Activity that is launched in a mode
122 other than <code>standard</code>, you use {@link android.test.SingleLaunchActivityTestCase}.
123</p>
124<h3 id="ActivityInstrumentationTestCase2">ActivityInstrumentationTestCase2</h3>
125<p>
126 The {@link android.test.ActivityInstrumentationTestCase2} test case class is designed to do
127 functional testing of one or more Activities in an application, using a normal system
128 infrastructure. It runs the Activities in a normal instance of the application under test,
129 using a standard system Context. It allows you to send mock Intents to the activity under
130 test, so you can use it to test an activity that responds to multiple types of intents, or
131 an activity that expects a certain type of data in the intent, or both. Notice, though, that it
132 does not allow mock Contexts or Applications, so you can not isolate the test from the rest of
133 a production system.
134</p>
135<h3 id="ActivityUnitTestCase">ActivityUnitTestCase</h3>
136<p>
137 The {@link android.test.ActivityUnitTestCase} test case class tests a single activity in
138 isolation. Before you start the activity, you can inject a mock Context or Application, or both.
139 You use it to run activity tests in isolation, and to do unit testing of methods
140 that do not interact with Android. You can not send mock Intents to the activity under test,
141 although you can call
142 {@link android.app.Activity#startActivity(Intent) Activity.startActivity(Intent)} and then
143 look at arguments that were received.
144</p>
145<h3 id="SingleLaunchActivityTestCase">SingleLaunchActivityTestCase</h3>
146<p>
147 The {@link android.test.SingleLaunchActivityTestCase} class is a convenience class for
148 testing a single activity in an environment that doesn't change from test to test.
149 It invokes {@link junit.framework.TestCase#setUp() setUp()} and
150 {@link junit.framework.TestCase#tearDown() tearDown()} only once, instead of once per
151 method call. It does not allow you to inject any mock objects.
152</p>
153<p>
154 This test case is useful for testing an activity that runs in a mode other than
155 <code>standard</code>. It ensures that the test fixture is not reset between tests. You
156 can then test that the activity handles multiple calls correctly.
157</p>
158<h3 id="MockObjectNotes">Mock objects and activity testing</h3>
159<p>
160 This section contains notes about the use of the mock objects defined in
161 {@link android.test.mock} with activity tests.
162</p>
163<p>
164 The mock object {@link android.test.mock.MockApplication} is only available for activity
165 testing if you use the {@link android.test.ActivityUnitTestCase} test case class.
166 By default, <code>ActivityUnitTestCase</code>, creates a hidden <code>MockApplication</code>
167 object that is used as the application under test. You can inject your own object using
168 {@link android.test.ActivityUnitTestCase#setApplication(Application) setApplication()}.
169</p>
170<h3 id="AssertionNotes">Assertions for activity testing</h3>
171<p>
172 {@link android.test.ViewAsserts} defines assertions for Views. You use it to verify the
173 alignment and position of View objects, and to look at the state of ViewGroup objects.
174</p>
175<h2 id="WhatToTest">What To Test</h2>
176<ul>
177 <li>
178 Input validation: Test that an activity responds correctly to input values in an
179 EditText View. Set up a keystroke sequence, send it to the activity, and then
180 use {@link android.view.View#findViewById(int)} to examine the state of the View. You can
181 verify that a valid keystroke sequence enables an OK button, while an invalid one leaves the
182 button disabled. You can also verify that the Activity responds to invalid input by
183 setting error messages in the View.
184 </li>
185 <li>
186 Lifecycle events: Test that each of your application's activities handles lifecycle events
187 correctly. In general, lifecycle events are actions, either from the system or from the
188 user, that trigger a callback method such as <code>onCreate()</code> or
189 <code>onClick()</code>. For example, an activity should respond to pause or destroy events
190 by saving its state. Remember that even a change in screen orientation causes the current
191 activity to be destroyed, so you should test that accidental device movements don't
192 accidentally lose the application state.
193 </li>
194 <li>
195 Intents: Test that each activity correctly handles the intents listed in the intent
196 filter specified in its manifest. You can use
197 {@link android.test.ActivityInstrumentationTestCase2} to send mock Intents to the
198 activity under test.
199 </li>
200 <li>
201 Runtime configuration changes: Test that each activity responds correctly to the
202 possible changes in the device's configuration while your application is running. These
203 include a change to the device's orientation, a change to the current language, and so
204 forth. Handling these changes is described in detail in the topic
205 <a href="{@docRoot}guide/topics/resources/runtime-changes.html">Handling Runtime
206 Changes</a>.
207 </li>
208 <li>
209 Screen sizes and resolutions: Before you publish your application, make sure to test it on
210 all of the screen sizes and densities on which you want it to run. You can test the
211 application on multiple sizes and densities using AVDs, or you can test your application
212 directly on the devices that you are targeting. For more information, see the topic
213 <a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a>.
214 </li>
215</ul>
216<h2 id="NextSteps">Next Steps</h2>
217<p>
218 To learn how to set up and run tests in Eclipse, please refer to
219<a href="{@docRoot}tools/testing/testing_eclipse.html">Testing from Eclipse with ADT</a>.
220 If you're not working in Eclipse, refer to
221<a href="{@docRoot}tools/testing/testing_otheride.html">Testing from Other IDEs</a>.
222</p>
223<p>
224 If you want a step-by-step introduction to testing activities, try the
225 <a href="{@docRoot}tools/testing/activity_test.html">Activity Testing Tutorial</a>, which
226 guides you through a testing scenario that you develop against an activity-oriented application.
227</p>
228<h2 id="UITesting">Appendix: UI Testing Notes</h2>
229<p>
230 The following sections have tips for testing the UI of your Android application, specifically
231 to help you handle actions that run in the UI thread, touch screen and keyboard events, and home
232 screen unlock during testing.
233</p>
234<h3 id="RunOnUIThread">Testing on the UI thread</h3>
235<p>
236 An application's activities run on the application's <strong>UI thread</strong>. Once the
237 UI is instantiated, for example in the activity's <code>onCreate()</code> method, then all
238 interactions with the UI must run in the UI thread. When you run the application normally, it
239 has access to the thread and does not have to do anything special.
240</p>
241<p>
242 This changes when you run tests against the application. With instrumentation-based classes,
243 you can invoke methods against the UI of the application under test. The other test classes
244 don't allow this. To run an entire test method on the UI thread, you can annotate the thread
Yorke Lee3df06dd2014-10-28 15:16:52 -0700245 with <code>@UiThreadTest</code>. Notice that this will run <em>all</em> of the method statements
Scott Main50e990c2012-06-21 17:14:39 -0700246 on the UI thread. Methods that do not interact with the UI are not allowed; for example, you
247 can't invoke <code>Instrumentation.waitForIdleSync()</code>.
248</p>
249<p>
250 To run a subset of a test method on the UI thread, create an anonymous class of type
251 <code>Runnable</code>, put the statements you want in the <code>run()</code> method, and
252 instantiate a new instance of the class as a parameter to the method
253 <code><em>appActivity</em>.runOnUiThread()</code>, where <code><em>appActivity</em></code> is
254 the instance of the application you are testing.
255</p>
256<p>
257 For example, this code instantiates an activity to test, requests focus (a UI action) for the
258 Spinner displayed by the activity, and then sends a key to it. Notice that the calls to
259 <code>waitForIdleSync</code> and <code>sendKeys</code> aren't allowed to run on the UI thread:
260</p>
261<pre>
262 private MyActivity mActivity; // MyActivity is the class name of the app under test
263 private Spinner mSpinner;
264
265 ...
266
267 protected void setUp() throws Exception {
268 super.setUp();
269 mInstrumentation = getInstrumentation();
270
271 mActivity = getActivity(); // get a references to the app under test
272
273 /*
274 * Get a reference to the main widget of the app under test, a Spinner
275 */
276 mSpinner = (Spinner) mActivity.findViewById(com.android.demo.myactivity.R.id.Spinner01);
277
278 ...
279
280 public void aTest() {
281 /*
282 * request focus for the Spinner, so that the test can send key events to it
283 * This request must be run on the UI thread. To do this, use the runOnUiThread method
284 * and pass it a Runnable that contains a call to requestFocus on the Spinner.
285 */
286 mActivity.runOnUiThread(new Runnable() {
287 public void run() {
288 mSpinner.requestFocus();
289 }
290 });
291
292 mInstrumentation.waitForIdleSync();
293
294 this.sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
295</pre>
296
297<h3 id="NotouchMode">Turning off touch mode</h3>
298<p>
299 To control the emulator or a device with key events you send from your tests, you must turn off
300 touch mode. If you do not do this, the key events are ignored.
301</p>
302<p>
303 To turn off touch mode, you invoke
304 <code>ActivityInstrumentationTestCase2.setActivityTouchMode(false)</code>
305 <em>before</em> you call <code>getActivity()</code> to start the activity. You must invoke the
306 method in a test method that is <em>not</em> running on the UI thread. For this reason, you
307 can't invoke the touch mode method from a test method that is annotated with
308 <code>@UIThread</code>. Instead, invoke the touch mode method from <code>setUp()</code>.
309</p>
310<h3 id="UnlockDevice">Unlocking the emulator or device</h3>
311<p>
312 You may find that UI tests don't work if the emulator's or device's home screen is disabled with
313 the keyguard pattern. This is because the application under test can't receive key events sent
314 by <code>sendKeys()</code>. The best way to avoid this is to start your emulator or device
315 first and then disable the keyguard for the home screen.
316</p>
317<p>
318 You can also explicitly disable the keyguard. To do this,
319 you need to add a permission in the manifest file (<code>AndroidManifest.xml</code>) and
320 then disable the keyguard in your application under test. Note, though, that you either have to
321 remove this before you publish your application, or you have to disable it with code in
322 the published application.
323</p>
324<p>
kmccormick76dfc022013-04-03 12:41:12 -0700325 To add the permission, add the element
Scott Main50e990c2012-06-21 17:14:39 -0700326 <code>&lt;uses-permission android:name="android.permission.DISABLE_KEYGUARD"/&gt;</code>
327 as a child of the <code>&lt;manifest&gt;</code> element. To disable the KeyGuard, add the
328 following code to the <code>onCreate()</code> method of activities you intend to test:
329</p>
330<pre>
331 mKeyGuardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
332 mLock = mKeyGuardManager.newKeyguardLock("<em>activity_classname</em>");
333 mLock.disableKeyguard();
334</pre>
335<p>where <code><em>activity_classname</em></code> is the class name of the activity.</p>
336<h3 id="UITestTroubleshooting">Troubleshooting UI tests</h3>
337<p>
338 This section lists some of the common test failures you may encounter in UI testing, and their
339 causes:
340</p>
341<dl>
342 <dt><code>WrongThreadException</code></dt>
343 <dd>
344 <p><strong>Problem:</strong></p>
345 For a failed test, the Failure Trace contains the following error message:
346 <code>
347 android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created
348 a view hierarchy can touch its views.
349 </code>
350 <p><strong>Probable Cause:</strong></p>
351 This error is common if you tried to send UI events to the UI thread from outside the UI
352 thread. This commonly happens if you send UI events from the test application, but you don't
353 use the <code>@UIThread</code> annotation or the <code>runOnUiThread()</code> method. The
354 test method tried to interact with the UI outside the UI thread.
355 <p><strong>Suggested Resolution:</strong></p>
356 Run the interaction on the UI thread. Use a test class that provides instrumentation. See
357 the previous section <a href="#RunOnUIThread">Testing on the UI Thread</a>
358 for more details.
359 </dd>
360 <dt><code>java.lang.RuntimeException</code></dt>
361 <dd>
362 <p><strong>Problem:</strong></p>
363 For a failed test, the Failure Trace contains the following error message:
364 <code>
365 java.lang.RuntimeException: This method can not be called from the main application thread
366 </code>
367 <p><strong>Probable Cause:</strong></p>
368 This error is common if your test method is annotated with <code>@UiThreadTest</code> but
369 then tries to do something outside the UI thread or tries to invoke
370 <code>runOnUiThread()</code>.
371 <p><strong>Suggested Resolution:</strong></p>
372 Remove the <code>@UiThreadTest</code> annotation, remove the <code>runOnUiThread()</code>
373 call, or re-factor your tests.
374 </dd>
375</dl>