quddusc | 2ef3952 | 2013-06-21 16:49:46 -0700 | [diff] [blame] | 1 | page.title=Creating Functional Tests |
| 2 | trainingnavtop=true |
| 3 | @jd:body |
| 4 | |
| 5 | <!-- This is the training bar --> |
| 6 | <div id="tb-wrapper"> |
| 7 | <div id="tb"> |
| 8 | |
| 9 | <h2>This lesson teaches you to</h2> |
| 10 | <ol> |
| 11 | <li><a href="#test_methods">Add Test Method to Validate Functional Behavior</a> |
| 12 | <ol> |
| 13 | <li><a href="#activitymonitor">Set Up an ActivityMonitor</a></li> |
| 14 | <li><a href="#keyinput">Send Keyboard Input Using Instrumentation</a></li> |
| 15 | </ol> |
| 16 | </li> |
| 17 | </ol> |
| 18 | |
| 19 | <h2>Try it out</h2> |
| 20 | <div class="download-box"> |
| 21 | <a href="http://developer.android.com/shareables/training/AndroidTestingFun.zip" |
| 22 | class="button">Download the demo</a> |
| 23 | <p class="filename">AndroidTestingFun.zip</p> |
| 24 | </div> |
| 25 | |
| 26 | </div> |
| 27 | </div> |
| 28 | <p>Functional testing involves verifying that individual application |
| 29 | components work together as expected by the user. For example, you can create a |
| 30 | functional test to verify that an {@link android.app.Activity} correctly |
| 31 | launches a target {@link android.app.Activity} when the user performs a UI |
| 32 | interaction.</p> |
| 33 | |
| 34 | <p>To create a functional test for your {@link android.app.Activity}, your test |
| 35 | class should extend {@link android.test.ActivityInstrumentationTestCase2}. |
| 36 | Unlike {@link android.test.ActivityUnitTestCase}, |
| 37 | tests in {@link android.test.ActivityInstrumentationTestCase2} can |
| 38 | communicate with the Android system and send keyboard input and click events to |
| 39 | the UI.</p> |
| 40 | |
| 41 | <p>For a complete test case example, take a look at |
| 42 | {@code SenderActivityTest.java} in the sample app.</p> |
| 43 | |
| 44 | <h2 id="test_methods">Add Test Method to Validate Functional Behavior</h2> |
| 45 | <p id="test_goals">Your functional testing goals might include:</p> |
| 46 | <ul> |
| 47 | <li>Verifying that a target {@link android.app.Activity} is started when a |
| 48 | UI control is pushed in the sender {@link android.app.Activity}.</li> |
| 49 | <li>Verifying that the target {@link android.app.Activity} displays the |
| 50 | correct data based on the user's input in the sender |
| 51 | {@link android.app.Activity}.</li> |
| 52 | </ul> |
| 53 | <p>You might implement your test method like this:</p> |
| 54 | |
| 55 | <pre> |
| 56 | @MediumTest |
| 57 | public void testSendMessageToReceiverActivity() { |
| 58 | final Button sendToReceiverButton = (Button) |
| 59 | mSenderActivity.findViewById(R.id.send_message_button); |
| 60 | |
| 61 | final EditText senderMessageEditText = (EditText) |
| 62 | mSenderActivity.findViewById(R.id.message_input_edit_text); |
| 63 | |
| 64 | // Set up an ActivityMonitor |
| 65 | ... |
| 66 | |
| 67 | // Send string input value |
| 68 | ... |
| 69 | |
| 70 | // Validate that ReceiverActivity is started |
| 71 | ... |
| 72 | |
| 73 | // Validate that ReceiverActivity has the correct data |
| 74 | ... |
| 75 | |
| 76 | // Remove the ActivityMonitor |
| 77 | ... |
| 78 | } |
| 79 | </pre> |
| 80 | <p>The test waits for an {@link android.app.Activity} that matches this monitor, |
| 81 | otherwise returns null after a timeout elapses. If {@code ReceiverActivity} was |
| 82 | started, the {@link android.app.Instrumentation.ActivityMonitor ActivityMonitor} |
| 83 | that you set |
| 84 | up earlier receives a hit. You can use the assertion methods to verify that |
| 85 | the {@code ReceiverActivity} is indeed started, and that the hit count on the |
| 86 | {@link android.app.Instrumentation.ActivityMonitor ActivityMonitor} incremented |
| 87 | as expected.</p> |
| 88 | |
| 89 | <h2 id="activitymonitor">Set up an ActivityMonitor</h2> |
| 90 | <p>To monitor a single {@link android.app.Activity} in your application, you |
| 91 | can register an {@link android.app.Instrumentation.ActivityMonitor ActivityMonitor}. |
| 92 | The {@link android.app.Instrumentation.ActivityMonitor ActivityMonitor} is |
| 93 | notified by the system whenever an {@link android.app.Activity} that matches your criteria is started. |
| 94 | If a match is found, the monitor’s hit count is updated.</p> |
| 95 | <p>Generally, to use an |
| 96 | {@link android.app.Instrumentation.ActivityMonitor ActivityMonitor}, you should:</p> |
| 97 | <ol> |
| 98 | <li>Retrieve the {@link android.app.Instrumentation} instance for your test |
| 99 | case by using the |
| 100 | {@link android.test.InstrumentationTestCase#getInstrumentation()} method.</li> |
| 101 | <li>Add an instance of {@link android.app.Instrumentation.ActivityMonitor} to |
| 102 | the current instrumentation using one of the {@link android.app.Instrumentation} |
| 103 | {@code addMonitor()} methods. The match criteria can be specified as an |
| 104 | {@link android.content.IntentFilter} or a class name string.</li> |
| 105 | <li>Wait for the {@link android.app.Activity} to start.</li> |
| 106 | <li>Verify that the monitor hits were incremented.</li> |
| 107 | <li>Remove the monitor.</li> |
| 108 | </ol> |
| 109 | <p>For example:</p> |
| 110 | <pre> |
| 111 | // Set up an ActivityMonitor |
| 112 | ActivityMonitor receiverActivityMonitor = |
| 113 | getInstrumentation().addMonitor(ReceiverActivity.class.getName(), |
| 114 | null, false); |
| 115 | |
| 116 | // Validate that ReceiverActivity is started |
| 117 | TouchUtils.clickView(this, sendToReceiverButton); |
| 118 | ReceiverActivity receiverActivity = (ReceiverActivity) |
| 119 | receiverActivityMonitor.waitForActivityWithTimeout(TIMEOUT_IN_MS); |
| 120 | assertNotNull("ReceiverActivity is null", receiverActivity); |
| 121 | assertEquals("Monitor for ReceiverActivity has not been called", |
| 122 | 1, receiverActivityMonitor.getHits()); |
| 123 | assertEquals("Activity is of wrong type", |
| 124 | ReceiverActivity.class, receiverActivity.getClass()); |
| 125 | |
| 126 | // Remove the ActivityMonitor |
| 127 | getInstrumentation().removeMonitor(receiverActivityMonitor); |
| 128 | </pre> |
| 129 | |
| 130 | <h2 id="keyinput">Send Keyboard Input Using Instrumentation</h2> |
| 131 | <p>If your {@link android.app.Activity} has an {@link android.widget.EditText} |
| 132 | field, you might want to test that users can enter values into the |
| 133 | {@link android.widget.EditText} object.</p> |
| 134 | <p>Generally, to send a string input value to an {@link android.widget.EditText} |
| 135 | object in {@link android.test.ActivityInstrumentationTestCase2}, you should:</p> |
| 136 | <ol> |
| 137 | <li>Use the {@link android.app.Instrumentation#runOnMainSync(java.lang.Runnable) runOnMainSync()} |
| 138 | method to run the {@link android.view.View#requestFocus()} call synchronously |
| 139 | in a loop. This way, the UI thread is blocked until focus is received.</li> |
| 140 | <li>Call {@link android.app.Instrumentation#waitForIdleSync()} method to wait |
| 141 | for the main thread to become idle (that is, have no more events to process).</li> |
| 142 | <li>Send a text string to the {@link android.widget.EditText} by calling |
| 143 | {@link android.app.Instrumentation#sendStringSync(java.lang.String) |
| 144 | sendStringSync()} and pass your input string as the parameter.</p> |
| 145 | </ol> |
| 146 | <p>For example:</p> |
| 147 | <pre> |
| 148 | // Send string input value |
| 149 | getInstrumentation().runOnMainSync(new Runnable() { |
| 150 | @Override |
| 151 | public void run() { |
| 152 | senderMessageEditText.requestFocus(); |
| 153 | } |
| 154 | }); |
| 155 | getInstrumentation().waitForIdleSync(); |
| 156 | getInstrumentation().sendStringSync("Hello Android!"); |
| 157 | getInstrumentation().waitForIdleSync(); |
| 158 | </pre> |
| 159 | |
| 160 | |
| 161 | |
| 162 | |
| 163 | |
| 164 | |
| 165 | |
| 166 | |