| Scott Main | 50e990c | 2012-06-21 17:14:39 -0700 | [diff] [blame] | 1 | page.title=Activity Testing |
| 2 | parent.title=Testing |
| 3 | parent.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> |
| kmccormick | 76dfc02 | 2013-04-03 12:41:12 -0700 | [diff] [blame] | 80 | Activity testing is particularly dependent on the Android instrumentation framework. |
| Scott Main | 50e990c | 2012-06-21 17:14:39 -0700 | [diff] [blame] | 81 | 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 Lee | 3df06dd | 2014-10-28 15:16:52 -0700 | [diff] [blame] | 245 | with <code>@UiThreadTest</code>. Notice that this will run <em>all</em> of the method statements |
| Scott Main | 50e990c | 2012-06-21 17:14:39 -0700 | [diff] [blame] | 246 | 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> |
| kmccormick | 76dfc02 | 2013-04-03 12:41:12 -0700 | [diff] [blame] | 325 | To add the permission, add the element |
| Scott Main | 50e990c | 2012-06-21 17:14:39 -0700 | [diff] [blame] | 326 | <code><uses-permission android:name="android.permission.DISABLE_KEYGUARD"/></code> |
| 327 | as a child of the <code><manifest></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> |