| page.title=Activity Testing | |
| parent.title=Testing | |
| parent.link=index.html | |
| @jd:body | |
| <div id="qv-wrapper"> | |
| <div id="qv"> | |
| <h2>In this document</h2> | |
| <ol> | |
| <li> | |
| <a href="#ActivityTestAPI">The Activity Testing API</a> | |
| <ol> | |
| <li> | |
| <a href="#ActivityInstrumentationTestCase2">ActivityInstrumentationTestCase2</a> | |
| </li> | |
| <li> | |
| <a href="#ActivityUnitTestCase">ActivityUnitTestCase</a> | |
| </li> | |
| <li> | |
| <a href="#SingleLaunchActivityTestCase">SingleLaunchActivityTestCase</a> | |
| </li> | |
| <li> | |
| <a href="#MockObjectNotes">Mock objects and activity testing</a> | |
| </li> | |
| <li> | |
| <a href="#AssertionNotes">Assertions for activity testing</a> | |
| </li> | |
| </ol> | |
| </li> | |
| <li> | |
| <a href="#WhatToTest">What to Test</a> | |
| </li> | |
| <li> | |
| <a href="#NextSteps">Next Steps</a> | |
| </li> | |
| <li> | |
| <a href="#UITesting">Appendix: UI Testing Notes</a> | |
| <ol> | |
| <li> | |
| <a href="#RunOnUIThread">Testing on the UI thread</a> | |
| </li> | |
| <li> | |
| <a href="#NotouchMode">Turning off touch mode</a> | |
| </li> | |
| <li> | |
| <a href="#UnlockDevice">Unlocking the Emulator or Device</a> | |
| </li> | |
| <li> | |
| <a href="#UITestTroubleshooting">Troubleshooting UI tests</a> | |
| </li> | |
| </ol> | |
| </li> | |
| </ol> | |
| <h2>Key Classes</h2> | |
| <ol> | |
| <li>{@link android.test.InstrumentationTestRunner}</li> | |
| <li>{@link android.test.ActivityInstrumentationTestCase2}</li> | |
| <li>{@link android.test.ActivityUnitTestCase}</li> | |
| </ol> | |
| <h2>Related Tutorials</h2> | |
| <ol> | |
| <li> | |
| <a href="{@docRoot}tools/testing/activity_test.html">Activity Testing Tutorial</a> | |
| </li> | |
| </ol> | |
| <h2>See Also</h2> | |
| <ol> | |
| <li> | |
| <a href="{@docRoot}tools/testing/testing_eclipse.html"> | |
| Testing from Eclipse with ADT</a> | |
| </li> | |
| <li> | |
| <a href="{@docRoot}tools/testing/testing_otheride.html"> | |
| Testing from Other IDEs</a> | |
| </li> | |
| </ol> | |
| </div> | |
| </div> | |
| <p> | |
| Activity testing is particularly dependent on the Android instrumentation framework. | |
| Unlike other components, activities have a complex lifecycle based on callback methods; these | |
| can't be invoked directly except by instrumentation. Also, the only way to send events to the | |
| user interface from a program is through instrumentation. | |
| </p> | |
| <p> | |
| This document describes how to test activities using instrumentation and other test | |
| facilities. The document assumes you have already read | |
| <a href="{@docRoot}tools/testing/testing_android.html">Testing Fundamentals</a>, | |
| the introduction to the Android testing and instrumentation framework. | |
| </p> | |
| <h2 id="ActivityTestAPI">The Activity Testing API</h2> | |
| <p> | |
| The activity testing API base class is {@link android.test.InstrumentationTestCase}, | |
| which provides instrumentation to the test case subclasses you use for Activities. | |
| </p> | |
| <p> | |
| For activity testing, this base class provides these functions: | |
| </p> | |
| <ul> | |
| <li> | |
| Lifecycle control: With instrumentation, you can start the activity under test, pause it, | |
| and destroy it, using methods provided by the test case classes. | |
| </li> | |
| <li> | |
| Dependency injection: Instrumentation allows you to create mock system objects such as | |
| Contexts or Applications and use them to run the activity under test. This | |
| helps you control the test environment and isolate it from production systems. You can | |
| also set up customized Intents and start an activity with them. | |
| </li> | |
| <li> | |
| User interface interaction: You use instrumentation to send keystrokes or touch events | |
| directly to the UI of the activity under test. | |
| </li> | |
| </ul> | |
| <p> | |
| The activity testing classes also provide the JUnit framework by extending | |
| {@link junit.framework.TestCase} and {@link junit.framework.Assert}. | |
| </p> | |
| <p> | |
| The two main testing subclasses are {@link android.test.ActivityInstrumentationTestCase2} and | |
| {@link android.test.ActivityUnitTestCase}. To test an Activity that is launched in a mode | |
| other than <code>standard</code>, you use {@link android.test.SingleLaunchActivityTestCase}. | |
| </p> | |
| <h3 id="ActivityInstrumentationTestCase2">ActivityInstrumentationTestCase2</h3> | |
| <p> | |
| The {@link android.test.ActivityInstrumentationTestCase2} test case class is designed to do | |
| functional testing of one or more Activities in an application, using a normal system | |
| infrastructure. It runs the Activities in a normal instance of the application under test, | |
| using a standard system Context. It allows you to send mock Intents to the activity under | |
| test, so you can use it to test an activity that responds to multiple types of intents, or | |
| an activity that expects a certain type of data in the intent, or both. Notice, though, that it | |
| does not allow mock Contexts or Applications, so you can not isolate the test from the rest of | |
| a production system. | |
| </p> | |
| <h3 id="ActivityUnitTestCase">ActivityUnitTestCase</h3> | |
| <p> | |
| The {@link android.test.ActivityUnitTestCase} test case class tests a single activity in | |
| isolation. Before you start the activity, you can inject a mock Context or Application, or both. | |
| You use it to run activity tests in isolation, and to do unit testing of methods | |
| that do not interact with Android. You can not send mock Intents to the activity under test, | |
| although you can call | |
| {@link android.app.Activity#startActivity(Intent) Activity.startActivity(Intent)} and then | |
| look at arguments that were received. | |
| </p> | |
| <h3 id="SingleLaunchActivityTestCase">SingleLaunchActivityTestCase</h3> | |
| <p> | |
| The {@link android.test.SingleLaunchActivityTestCase} class is a convenience class for | |
| testing a single activity in an environment that doesn't change from test to test. | |
| It invokes {@link junit.framework.TestCase#setUp() setUp()} and | |
| {@link junit.framework.TestCase#tearDown() tearDown()} only once, instead of once per | |
| method call. It does not allow you to inject any mock objects. | |
| </p> | |
| <p> | |
| This test case is useful for testing an activity that runs in a mode other than | |
| <code>standard</code>. It ensures that the test fixture is not reset between tests. You | |
| can then test that the activity handles multiple calls correctly. | |
| </p> | |
| <h3 id="MockObjectNotes">Mock objects and activity testing</h3> | |
| <p> | |
| This section contains notes about the use of the mock objects defined in | |
| {@link android.test.mock} with activity tests. | |
| </p> | |
| <p> | |
| The mock object {@link android.test.mock.MockApplication} is only available for activity | |
| testing if you use the {@link android.test.ActivityUnitTestCase} test case class. | |
| By default, <code>ActivityUnitTestCase</code>, creates a hidden <code>MockApplication</code> | |
| object that is used as the application under test. You can inject your own object using | |
| {@link android.test.ActivityUnitTestCase#setApplication(Application) setApplication()}. | |
| </p> | |
| <h3 id="AssertionNotes">Assertions for activity testing</h3> | |
| <p> | |
| {@link android.test.ViewAsserts} defines assertions for Views. You use it to verify the | |
| alignment and position of View objects, and to look at the state of ViewGroup objects. | |
| </p> | |
| <h2 id="WhatToTest">What To Test</h2> | |
| <ul> | |
| <li> | |
| Input validation: Test that an activity responds correctly to input values in an | |
| EditText View. Set up a keystroke sequence, send it to the activity, and then | |
| use {@link android.view.View#findViewById(int)} to examine the state of the View. You can | |
| verify that a valid keystroke sequence enables an OK button, while an invalid one leaves the | |
| button disabled. You can also verify that the Activity responds to invalid input by | |
| setting error messages in the View. | |
| </li> | |
| <li> | |
| Lifecycle events: Test that each of your application's activities handles lifecycle events | |
| correctly. In general, lifecycle events are actions, either from the system or from the | |
| user, that trigger a callback method such as <code>onCreate()</code> or | |
| <code>onClick()</code>. For example, an activity should respond to pause or destroy events | |
| by saving its state. Remember that even a change in screen orientation causes the current | |
| activity to be destroyed, so you should test that accidental device movements don't | |
| accidentally lose the application state. | |
| </li> | |
| <li> | |
| Intents: Test that each activity correctly handles the intents listed in the intent | |
| filter specified in its manifest. You can use | |
| {@link android.test.ActivityInstrumentationTestCase2} to send mock Intents to the | |
| activity under test. | |
| </li> | |
| <li> | |
| Runtime configuration changes: Test that each activity responds correctly to the | |
| possible changes in the device's configuration while your application is running. These | |
| include a change to the device's orientation, a change to the current language, and so | |
| forth. Handling these changes is described in detail in the topic | |
| <a href="{@docRoot}guide/topics/resources/runtime-changes.html">Handling Runtime | |
| Changes</a>. | |
| </li> | |
| <li> | |
| Screen sizes and resolutions: Before you publish your application, make sure to test it on | |
| all of the screen sizes and densities on which you want it to run. You can test the | |
| application on multiple sizes and densities using AVDs, or you can test your application | |
| directly on the devices that you are targeting. For more information, see the topic | |
| <a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a>. | |
| </li> | |
| </ul> | |
| <h2 id="NextSteps">Next Steps</h2> | |
| <p> | |
| To learn how to set up and run tests in Eclipse, please refer to | |
| <a href="{@docRoot}tools/testing/testing_eclipse.html">Testing from Eclipse with ADT</a>. | |
| If you're not working in Eclipse, refer to | |
| <a href="{@docRoot}tools/testing/testing_otheride.html">Testing from Other IDEs</a>. | |
| </p> | |
| <p> | |
| If you want a step-by-step introduction to testing activities, try the | |
| <a href="{@docRoot}tools/testing/activity_test.html">Activity Testing Tutorial</a>, which | |
| guides you through a testing scenario that you develop against an activity-oriented application. | |
| </p> | |
| <h2 id="UITesting">Appendix: UI Testing Notes</h2> | |
| <p> | |
| The following sections have tips for testing the UI of your Android application, specifically | |
| to help you handle actions that run in the UI thread, touch screen and keyboard events, and home | |
| screen unlock during testing. | |
| </p> | |
| <h3 id="RunOnUIThread">Testing on the UI thread</h3> | |
| <p> | |
| An application's activities run on the application's <strong>UI thread</strong>. Once the | |
| UI is instantiated, for example in the activity's <code>onCreate()</code> method, then all | |
| interactions with the UI must run in the UI thread. When you run the application normally, it | |
| has access to the thread and does not have to do anything special. | |
| </p> | |
| <p> | |
| This changes when you run tests against the application. With instrumentation-based classes, | |
| you can invoke methods against the UI of the application under test. The other test classes | |
| don't allow this. To run an entire test method on the UI thread, you can annotate the thread | |
| with <code>@UiThreadTest</code>. Notice that this will run <em>all</em> of the method statements | |
| on the UI thread. Methods that do not interact with the UI are not allowed; for example, you | |
| can't invoke <code>Instrumentation.waitForIdleSync()</code>. | |
| </p> | |
| <p> | |
| To run a subset of a test method on the UI thread, create an anonymous class of type | |
| <code>Runnable</code>, put the statements you want in the <code>run()</code> method, and | |
| instantiate a new instance of the class as a parameter to the method | |
| <code><em>appActivity</em>.runOnUiThread()</code>, where <code><em>appActivity</em></code> is | |
| the instance of the application you are testing. | |
| </p> | |
| <p> | |
| For example, this code instantiates an activity to test, requests focus (a UI action) for the | |
| Spinner displayed by the activity, and then sends a key to it. Notice that the calls to | |
| <code>waitForIdleSync</code> and <code>sendKeys</code> aren't allowed to run on the UI thread: | |
| </p> | |
| <pre> | |
| private MyActivity mActivity; // MyActivity is the class name of the app under test | |
| private Spinner mSpinner; | |
| ... | |
| protected void setUp() throws Exception { | |
| super.setUp(); | |
| mInstrumentation = getInstrumentation(); | |
| mActivity = getActivity(); // get a references to the app under test | |
| /* | |
| * Get a reference to the main widget of the app under test, a Spinner | |
| */ | |
| mSpinner = (Spinner) mActivity.findViewById(com.android.demo.myactivity.R.id.Spinner01); | |
| ... | |
| public void aTest() { | |
| /* | |
| * request focus for the Spinner, so that the test can send key events to it | |
| * This request must be run on the UI thread. To do this, use the runOnUiThread method | |
| * and pass it a Runnable that contains a call to requestFocus on the Spinner. | |
| */ | |
| mActivity.runOnUiThread(new Runnable() { | |
| public void run() { | |
| mSpinner.requestFocus(); | |
| } | |
| }); | |
| mInstrumentation.waitForIdleSync(); | |
| this.sendKeys(KeyEvent.KEYCODE_DPAD_CENTER); | |
| </pre> | |
| <h3 id="NotouchMode">Turning off touch mode</h3> | |
| <p> | |
| To control the emulator or a device with key events you send from your tests, you must turn off | |
| touch mode. If you do not do this, the key events are ignored. | |
| </p> | |
| <p> | |
| To turn off touch mode, you invoke | |
| <code>ActivityInstrumentationTestCase2.setActivityTouchMode(false)</code> | |
| <em>before</em> you call <code>getActivity()</code> to start the activity. You must invoke the | |
| method in a test method that is <em>not</em> running on the UI thread. For this reason, you | |
| can't invoke the touch mode method from a test method that is annotated with | |
| <code>@UIThread</code>. Instead, invoke the touch mode method from <code>setUp()</code>. | |
| </p> | |
| <h3 id="UnlockDevice">Unlocking the emulator or device</h3> | |
| <p> | |
| You may find that UI tests don't work if the emulator's or device's home screen is disabled with | |
| the keyguard pattern. This is because the application under test can't receive key events sent | |
| by <code>sendKeys()</code>. The best way to avoid this is to start your emulator or device | |
| first and then disable the keyguard for the home screen. | |
| </p> | |
| <p> | |
| You can also explicitly disable the keyguard. To do this, | |
| you need to add a permission in the manifest file (<code>AndroidManifest.xml</code>) and | |
| then disable the keyguard in your application under test. Note, though, that you either have to | |
| remove this before you publish your application, or you have to disable it with code in | |
| the published application. | |
| </p> | |
| <p> | |
| To add the permission, add the element | |
| <code><uses-permission android:name="android.permission.DISABLE_KEYGUARD"/></code> | |
| as a child of the <code><manifest></code> element. To disable the KeyGuard, add the | |
| following code to the <code>onCreate()</code> method of activities you intend to test: | |
| </p> | |
| <pre> | |
| mKeyGuardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE); | |
| mLock = mKeyGuardManager.newKeyguardLock("<em>activity_classname</em>"); | |
| mLock.disableKeyguard(); | |
| </pre> | |
| <p>where <code><em>activity_classname</em></code> is the class name of the activity.</p> | |
| <h3 id="UITestTroubleshooting">Troubleshooting UI tests</h3> | |
| <p> | |
| This section lists some of the common test failures you may encounter in UI testing, and their | |
| causes: | |
| </p> | |
| <dl> | |
| <dt><code>WrongThreadException</code></dt> | |
| <dd> | |
| <p><strong>Problem:</strong></p> | |
| For a failed test, the Failure Trace contains the following error message: | |
| <code> | |
| android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created | |
| a view hierarchy can touch its views. | |
| </code> | |
| <p><strong>Probable Cause:</strong></p> | |
| This error is common if you tried to send UI events to the UI thread from outside the UI | |
| thread. This commonly happens if you send UI events from the test application, but you don't | |
| use the <code>@UIThread</code> annotation or the <code>runOnUiThread()</code> method. The | |
| test method tried to interact with the UI outside the UI thread. | |
| <p><strong>Suggested Resolution:</strong></p> | |
| Run the interaction on the UI thread. Use a test class that provides instrumentation. See | |
| the previous section <a href="#RunOnUIThread">Testing on the UI Thread</a> | |
| for more details. | |
| </dd> | |
| <dt><code>java.lang.RuntimeException</code></dt> | |
| <dd> | |
| <p><strong>Problem:</strong></p> | |
| For a failed test, the Failure Trace contains the following error message: | |
| <code> | |
| java.lang.RuntimeException: This method can not be called from the main application thread | |
| </code> | |
| <p><strong>Probable Cause:</strong></p> | |
| This error is common if your test method is annotated with <code>@UiThreadTest</code> but | |
| then tries to do something outside the UI thread or tries to invoke | |
| <code>runOnUiThread()</code>. | |
| <p><strong>Suggested Resolution:</strong></p> | |
| Remove the <code>@UiThreadTest</code> annotation, remove the <code>runOnUiThread()</code> | |
| call, or re-factor your tests. | |
| </dd> | |
| </dl> |